Completed
Pull Request — master (#3218)
by Vars
46:46 queued 34:29
created
apps/user_ldap/lib/Connection.php 1 patch
Indentation   +569 added lines, -569 removed lines patch added patch discarded remove patch
@@ -52,574 +52,574 @@
 block discarded – undo
52 52
  * @property string ldapUuidGroupAttribute
53 53
  */
54 54
 class Connection extends LDAPUtility {
55
-	private $ldapConnectionRes = null;
56
-	private $configPrefix;
57
-	private $configID;
58
-	private $configured = false;
59
-	private $hasPagedResultSupport = true;
60
-	//whether connection should be kept on __destruct
61
-	private $dontDestruct = false;
62
-
63
-	/**
64
-	 * @var bool runtime flag that indicates whether supported primary groups are available
65
-	 */
66
-	public $hasPrimaryGroups = true;
67
-
68
-	/**
69
-	 * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
70
-	 */
71
-	public $hasGidNumber = true;
72
-
73
-	//cache handler
74
-	protected $cache;
75
-
76
-	/** @var Configuration settings handler **/
77
-	protected $configuration;
78
-
79
-	protected $doNotValidate = false;
80
-
81
-	protected $ignoreValidation = false;
82
-
83
-	/**
84
-	 * Constructor
85
-	 * @param ILDAPWrapper $ldap
86
-	 * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
87
-	 * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
88
-	 */
89
-	public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
90
-		parent::__construct($ldap);
91
-		$this->configPrefix = $configPrefix;
92
-		$this->configID = $configID;
93
-		$this->configuration = new Configuration($configPrefix,
94
-												 !is_null($configID));
95
-		$memcache = \OC::$server->getMemCacheFactory();
96
-		if($memcache->isAvailable()) {
97
-			$this->cache = $memcache->create();
98
-		}
99
-		$helper = new Helper(\OC::$server->getConfig());
100
-		$this->doNotValidate = !in_array($this->configPrefix,
101
-			$helper->getServerConfigurationPrefixes());
102
-		$this->hasPagedResultSupport =
103
-			intval($this->configuration->ldapPagingSize) !== 0
104
-			|| $this->ldap->hasPagedResultSupport();
105
-	}
106
-
107
-	public function __destruct() {
108
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
109
-			@$this->ldap->unbind($this->ldapConnectionRes);
110
-		};
111
-	}
112
-
113
-	/**
114
-	 * defines behaviour when the instance is cloned
115
-	 */
116
-	public function __clone() {
117
-		$this->configuration = new Configuration($this->configPrefix,
118
-												 !is_null($this->configID));
119
-		$this->ldapConnectionRes = null;
120
-		$this->dontDestruct = true;
121
-	}
122
-
123
-	/**
124
-	 * @param string $name
125
-	 * @return bool|mixed|void
126
-	 */
127
-	public function __get($name) {
128
-		if(!$this->configured) {
129
-			$this->readConfiguration();
130
-		}
131
-
132
-		if($name === 'hasPagedResultSupport') {
133
-			return $this->hasPagedResultSupport;
134
-		}
135
-
136
-		return $this->configuration->$name;
137
-	}
138
-
139
-	/**
140
-	 * @param string $name
141
-	 * @param mixed $value
142
-	 */
143
-	public function __set($name, $value) {
144
-		$this->doNotValidate = false;
145
-		$before = $this->configuration->$name;
146
-		$this->configuration->$name = $value;
147
-		$after = $this->configuration->$name;
148
-		if($before !== $after) {
149
-			if ($this->configID !== '') {
150
-				$this->configuration->saveConfiguration();
151
-			}
152
-			$this->validateConfiguration();
153
-		}
154
-	}
155
-
156
-	/**
157
-	 * sets whether the result of the configuration validation shall
158
-	 * be ignored when establishing the connection. Used by the Wizard
159
-	 * in early configuration state.
160
-	 * @param bool $state
161
-	 */
162
-	public function setIgnoreValidation($state) {
163
-		$this->ignoreValidation = (bool)$state;
164
-	}
165
-
166
-	/**
167
-	 * initializes the LDAP backend
168
-	 * @param bool $force read the config settings no matter what
169
-	 */
170
-	public function init($force = false) {
171
-		$this->readConfiguration($force);
172
-		$this->establishConnection();
173
-	}
174
-
175
-	/**
176
-	 * Returns the LDAP handler
177
-	 */
178
-	public function getConnectionResource() {
179
-		if(!$this->ldapConnectionRes) {
180
-			$this->init();
181
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
182
-			$this->ldapConnectionRes = null;
183
-			$this->establishConnection();
184
-		}
185
-		if(is_null($this->ldapConnectionRes)) {
186
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
187
-			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
188
-		}
189
-		return $this->ldapConnectionRes;
190
-	}
191
-
192
-	/**
193
-	 * resets the connection resource
194
-	 */
195
-	public function resetConnectionResource() {
196
-		if(!is_null($this->ldapConnectionRes)) {
197
-			@$this->ldap->unbind($this->ldapConnectionRes);
198
-			$this->ldapConnectionRes = null;
199
-		}
200
-	}
201
-
202
-	/**
203
-	 * @param string|null $key
204
-	 * @return string
205
-	 */
206
-	private function getCacheKey($key) {
207
-		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
208
-		if(is_null($key)) {
209
-			return $prefix;
210
-		}
211
-		return $prefix.md5($key);
212
-	}
213
-
214
-	/**
215
-	 * @param string $key
216
-	 * @return mixed|null
217
-	 */
218
-	public function getFromCache($key) {
219
-		if(!$this->configured) {
220
-			$this->readConfiguration();
221
-		}
222
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
223
-			return null;
224
-		}
225
-		$key = $this->getCacheKey($key);
226
-
227
-		return json_decode(base64_decode($this->cache->get($key)), true);
228
-	}
229
-
230
-	/**
231
-	 * @param string $key
232
-	 * @param mixed $value
233
-	 *
234
-	 * @return string
235
-	 */
236
-	public function writeToCache($key, $value) {
237
-		if(!$this->configured) {
238
-			$this->readConfiguration();
239
-		}
240
-		if(is_null($this->cache)
241
-			|| !$this->configuration->ldapCacheTTL
242
-			|| !$this->configuration->ldapConfigurationActive) {
243
-			return null;
244
-		}
245
-		$key   = $this->getCacheKey($key);
246
-		$value = base64_encode(json_encode($value));
247
-		$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
248
-	}
249
-
250
-	public function clearCache() {
251
-		if(!is_null($this->cache)) {
252
-			$this->cache->clear($this->getCacheKey(null));
253
-		}
254
-	}
255
-
256
-	/**
257
-	 * Caches the general LDAP configuration.
258
-	 * @param bool $force optional. true, if the re-read should be forced. defaults
259
-	 * to false.
260
-	 * @return null
261
-	 */
262
-	private function readConfiguration($force = false) {
263
-		if((!$this->configured || $force) && !is_null($this->configID)) {
264
-			$this->configuration->readConfiguration();
265
-			$this->configured = $this->validateConfiguration();
266
-		}
267
-	}
268
-
269
-	/**
270
-	 * set LDAP configuration with values delivered by an array, not read from configuration
271
-	 * @param array $config array that holds the config parameters in an associated array
272
-	 * @param array &$setParameters optional; array where the set fields will be given to
273
-	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
274
-	 */
275
-	public function setConfiguration($config, &$setParameters = null) {
276
-		if(is_null($setParameters)) {
277
-			$setParameters = array();
278
-		}
279
-		$this->doNotValidate = false;
280
-		$this->configuration->setConfiguration($config, $setParameters);
281
-		if(count($setParameters) > 0) {
282
-			$this->configured = $this->validateConfiguration();
283
-		}
284
-
285
-
286
-		return $this->configured;
287
-	}
288
-
289
-	/**
290
-	 * saves the current Configuration in the database and empties the
291
-	 * cache
292
-	 * @return null
293
-	 */
294
-	public function saveConfiguration() {
295
-		$this->configuration->saveConfiguration();
296
-		$this->clearCache();
297
-	}
298
-
299
-	/**
300
-	 * get the current LDAP configuration
301
-	 * @return array
302
-	 */
303
-	public function getConfiguration() {
304
-		$this->readConfiguration();
305
-		$config = $this->configuration->getConfiguration();
306
-		$cta = $this->configuration->getConfigTranslationArray();
307
-		$result = array();
308
-		foreach($cta as $dbkey => $configkey) {
309
-			switch($configkey) {
310
-				case 'homeFolderNamingRule':
311
-					if(strpos($config[$configkey], 'attr:') === 0) {
312
-						$result[$dbkey] = substr($config[$configkey], 5);
313
-					} else {
314
-						$result[$dbkey] = '';
315
-					}
316
-					break;
317
-				case 'ldapBase':
318
-				case 'ldapBaseUsers':
319
-				case 'ldapBaseGroups':
320
-				case 'ldapAttributesForUserSearch':
321
-				case 'ldapAttributesForGroupSearch':
322
-					if(is_array($config[$configkey])) {
323
-						$result[$dbkey] = implode("\n", $config[$configkey]);
324
-						break;
325
-					} //else follows default
326
-				default:
327
-					$result[$dbkey] = $config[$configkey];
328
-			}
329
-		}
330
-		return $result;
331
-	}
332
-
333
-	private function doSoftValidation() {
334
-		//if User or Group Base are not set, take over Base DN setting
335
-		foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
336
-			$val = $this->configuration->$keyBase;
337
-			if(empty($val)) {
338
-				$this->configuration->$keyBase = $this->configuration->ldapBase;
339
-			}
340
-		}
341
-
342
-		foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
343
-					  'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
344
-				as $expertSetting => $effectiveSetting) {
345
-			$uuidOverride = $this->configuration->$expertSetting;
346
-			if(!empty($uuidOverride)) {
347
-				$this->configuration->$effectiveSetting = $uuidOverride;
348
-			} else {
349
-				$uuidAttributes = array('auto', 'entryuuid', 'nsuniqueid',
350
-										'objectguid', 'guid', 'ipauniqueid');
351
-				if(!in_array($this->configuration->$effectiveSetting,
352
-							$uuidAttributes)
353
-					&& (!is_null($this->configID))) {
354
-					$this->configuration->$effectiveSetting = 'auto';
355
-					$this->configuration->saveConfiguration();
356
-					\OCP\Util::writeLog('user_ldap',
357
-										'Illegal value for the '.
358
-										$effectiveSetting.', '.'reset to '.
359
-										'autodetect.', \OCP\Util::INFO);
360
-				}
361
-
362
-			}
363
-		}
364
-
365
-		$backupPort = intval($this->configuration->ldapBackupPort);
366
-		if ($backupPort <= 0) {
367
-			$this->configuration->backupPort = $this->configuration->ldapPort;
368
-		}
369
-
370
-		//make sure empty search attributes are saved as simple, empty array
371
-		$saKeys = array('ldapAttributesForUserSearch',
372
-						'ldapAttributesForGroupSearch');
373
-		foreach($saKeys as $key) {
374
-			$val = $this->configuration->$key;
375
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
376
-				$this->configuration->$key = array();
377
-			}
378
-		}
379
-
380
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
381
-			&& $this->configuration->ldapTLS) {
382
-			$this->configuration->ldapTLS = false;
383
-			\OCP\Util::writeLog('user_ldap',
384
-								'LDAPS (already using secure connection) and '.
385
-								'TLS do not work together. Switched off TLS.',
386
-								\OCP\Util::INFO);
387
-		}
388
-	}
389
-
390
-	/**
391
-	 * @return bool
392
-	 */
393
-	private function doCriticalValidation() {
394
-		$configurationOK = true;
395
-		$errorStr = 'Configuration Error (prefix '.
396
-					strval($this->configPrefix).'): ';
397
-
398
-		//options that shall not be empty
399
-		$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
400
-						 'ldapGroupDisplayName', 'ldapLoginFilter');
401
-		foreach($options as $key) {
402
-			$val = $this->configuration->$key;
403
-			if(empty($val)) {
404
-				switch($key) {
405
-					case 'ldapHost':
406
-						$subj = 'LDAP Host';
407
-						break;
408
-					case 'ldapPort':
409
-						$subj = 'LDAP Port';
410
-						break;
411
-					case 'ldapUserDisplayName':
412
-						$subj = 'LDAP User Display Name';
413
-						break;
414
-					case 'ldapGroupDisplayName':
415
-						$subj = 'LDAP Group Display Name';
416
-						break;
417
-					case 'ldapLoginFilter':
418
-						$subj = 'LDAP Login Filter';
419
-						break;
420
-					default:
421
-						$subj = $key;
422
-						break;
423
-				}
424
-				$configurationOK = false;
425
-				\OCP\Util::writeLog('user_ldap',
426
-									$errorStr.'No '.$subj.' given!',
427
-									\OCP\Util::WARN);
428
-			}
429
-		}
430
-
431
-		//combinations
432
-		$agent = $this->configuration->ldapAgentName;
433
-		$pwd = $this->configuration->ldapAgentPassword;
434
-		if (
435
-			($agent === ''  && $pwd !== '')
436
-			|| ($agent !== '' && $pwd === '')
437
-		) {
438
-			\OCP\Util::writeLog('user_ldap',
439
-								$errorStr.'either no password is given for the'.
440
-								'user agent or a password is given, but not an'.
441
-								'LDAP agent.',
442
-				\OCP\Util::WARN);
443
-			$configurationOK = false;
444
-		}
445
-
446
-		$base = $this->configuration->ldapBase;
447
-		$baseUsers = $this->configuration->ldapBaseUsers;
448
-		$baseGroups = $this->configuration->ldapBaseGroups;
449
-
450
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
451
-			\OCP\Util::writeLog('user_ldap',
452
-								$errorStr.'Not a single Base DN given.',
453
-								\OCP\Util::WARN);
454
-			$configurationOK = false;
455
-		}
456
-
457
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
458
-		   === false) {
459
-			\OCP\Util::writeLog('user_ldap',
460
-								$errorStr.'login filter does not contain %uid '.
461
-								'place holder.',
462
-								\OCP\Util::WARN);
463
-			$configurationOK = false;
464
-		}
465
-
466
-		return $configurationOK;
467
-	}
468
-
469
-	/**
470
-	 * Validates the user specified configuration
471
-	 * @return bool true if configuration seems OK, false otherwise
472
-	 */
473
-	private function validateConfiguration() {
474
-
475
-		if($this->doNotValidate) {
476
-			//don't do a validation if it is a new configuration with pure
477
-			//default values. Will be allowed on changes via __set or
478
-			//setConfiguration
479
-			return false;
480
-		}
481
-
482
-		// first step: "soft" checks: settings that are not really
483
-		// necessary, but advisable. If left empty, give an info message
484
-		$this->doSoftValidation();
485
-
486
-		//second step: critical checks. If left empty or filled wrong, mark as
487
-		//not configured and give a warning.
488
-		return $this->doCriticalValidation();
489
-	}
490
-
491
-
492
-	/**
493
-	 * Connects and Binds to LDAP
494
-	 */
495
-	private function establishConnection() {
496
-		if(!$this->configuration->ldapConfigurationActive) {
497
-			return null;
498
-		}
499
-		static $phpLDAPinstalled = true;
500
-		if(!$phpLDAPinstalled) {
501
-			return false;
502
-		}
503
-		if(!$this->ignoreValidation && !$this->configured) {
504
-			\OCP\Util::writeLog('user_ldap',
505
-								'Configuration is invalid, cannot connect',
506
-								\OCP\Util::WARN);
507
-			return false;
508
-		}
509
-		if(!$this->ldapConnectionRes) {
510
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
511
-				$phpLDAPinstalled = false;
512
-				\OCP\Util::writeLog('user_ldap',
513
-									'function ldap_connect is not available. Make '.
514
-									'sure that the PHP ldap module is installed.',
515
-									\OCP\Util::ERROR);
516
-
517
-				return false;
518
-			}
519
-			if($this->configuration->turnOffCertCheck) {
520
-				if(putenv('LDAPTLS_REQCERT=never')) {
521
-					\OCP\Util::writeLog('user_ldap',
522
-						'Turned off SSL certificate validation successfully.',
523
-						\OCP\Util::DEBUG);
524
-				} else {
525
-					\OCP\Util::writeLog('user_ldap',
526
-										'Could not turn off SSL certificate validation.',
527
-										\OCP\Util::WARN);
528
-				}
529
-			}
530
-
531
-			$bindStatus = false;
532
-			$error = -1;
533
-			try {
534
-				if (!$this->configuration->ldapOverrideMainServer
535
-					&& !$this->getFromCache('overrideMainServer')
536
-				) {
537
-					$this->doConnect($this->configuration->ldapHost,
538
-						$this->configuration->ldapPort);
539
-					$bindStatus = $this->bind();
540
-					$error = $this->ldap->isResource($this->ldapConnectionRes) ?
541
-						$this->ldap->errno($this->ldapConnectionRes) : -1;
542
-				}
543
-				if($bindStatus === true) {
544
-					return $bindStatus;
545
-				}
546
-			} catch (\OC\ServerNotAvailableException $e) {
547
-				if(trim($this->configuration->ldapBackupHost) === "") {
548
-					throw $e;
549
-				}
550
-			}
551
-
552
-			//if LDAP server is not reachable, try the Backup (Replica!) Server
553
-			if(    $error !== 0
554
-				|| $this->configuration->ldapOverrideMainServer
555
-				|| $this->getFromCache('overrideMainServer'))
556
-			{
557
-				$this->doConnect($this->configuration->ldapBackupHost,
558
-								 $this->configuration->ldapBackupPort);
559
-				$bindStatus = $this->bind();
560
-				if($bindStatus && $error === -1 && !$this->getFromCache('overrideMainServer')) {
561
-					//when bind to backup server succeeded and failed to main server,
562
-					//skip contacting him until next cache refresh
563
-					$this->writeToCache('overrideMainServer', true);
564
-				}
565
-			}
566
-			return $bindStatus;
567
-		}
568
-		return null;
569
-	}
570
-
571
-	/**
572
-	 * @param string $host
573
-	 * @param string $port
574
-	 * @return bool
575
-	 * @throws \OC\ServerNotAvailableException
576
-	 */
577
-	private function doConnect($host, $port) {
578
-		if ($host === '') {
579
-			return false;
580
-		}
581
-		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
582
-		if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
583
-			if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
584
-				if($this->configuration->ldapTLS) {
585
-					$this->ldap->startTls($this->ldapConnectionRes);
586
-				}
587
-			}
588
-		} else {
589
-			throw new \OC\ServerNotAvailableException('Could not set required LDAP Protocol version.');
590
-		}
591
-		return true;
592
-	}
593
-
594
-	/**
595
-	 * Binds to LDAP
596
-	 */
597
-	public function bind() {
598
-		static $getConnectionResourceAttempt = false;
599
-		if(!$this->configuration->ldapConfigurationActive) {
600
-			return false;
601
-		}
602
-		if($getConnectionResourceAttempt) {
603
-			$getConnectionResourceAttempt = false;
604
-			return false;
605
-		}
606
-		$getConnectionResourceAttempt = true;
607
-		$cr = $this->getConnectionResource();
608
-		$getConnectionResourceAttempt = false;
609
-		if(!$this->ldap->isResource($cr)) {
610
-			return false;
611
-		}
612
-		$ldapLogin = @$this->ldap->bind($cr,
613
-										$this->configuration->ldapAgentName,
614
-										$this->configuration->ldapAgentPassword);
615
-		if(!$ldapLogin) {
616
-			\OCP\Util::writeLog('user_ldap',
617
-				'Bind failed: ' . $this->ldap->errno($cr) . ': ' . $this->ldap->error($cr),
618
-				\OCP\Util::WARN);
619
-			$this->ldapConnectionRes = null;
620
-			return false;
621
-		}
622
-		return true;
623
-	}
55
+    private $ldapConnectionRes = null;
56
+    private $configPrefix;
57
+    private $configID;
58
+    private $configured = false;
59
+    private $hasPagedResultSupport = true;
60
+    //whether connection should be kept on __destruct
61
+    private $dontDestruct = false;
62
+
63
+    /**
64
+     * @var bool runtime flag that indicates whether supported primary groups are available
65
+     */
66
+    public $hasPrimaryGroups = true;
67
+
68
+    /**
69
+     * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
70
+     */
71
+    public $hasGidNumber = true;
72
+
73
+    //cache handler
74
+    protected $cache;
75
+
76
+    /** @var Configuration settings handler **/
77
+    protected $configuration;
78
+
79
+    protected $doNotValidate = false;
80
+
81
+    protected $ignoreValidation = false;
82
+
83
+    /**
84
+     * Constructor
85
+     * @param ILDAPWrapper $ldap
86
+     * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
87
+     * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
88
+     */
89
+    public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
90
+        parent::__construct($ldap);
91
+        $this->configPrefix = $configPrefix;
92
+        $this->configID = $configID;
93
+        $this->configuration = new Configuration($configPrefix,
94
+                                                    !is_null($configID));
95
+        $memcache = \OC::$server->getMemCacheFactory();
96
+        if($memcache->isAvailable()) {
97
+            $this->cache = $memcache->create();
98
+        }
99
+        $helper = new Helper(\OC::$server->getConfig());
100
+        $this->doNotValidate = !in_array($this->configPrefix,
101
+            $helper->getServerConfigurationPrefixes());
102
+        $this->hasPagedResultSupport =
103
+            intval($this->configuration->ldapPagingSize) !== 0
104
+            || $this->ldap->hasPagedResultSupport();
105
+    }
106
+
107
+    public function __destruct() {
108
+        if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
109
+            @$this->ldap->unbind($this->ldapConnectionRes);
110
+        };
111
+    }
112
+
113
+    /**
114
+     * defines behaviour when the instance is cloned
115
+     */
116
+    public function __clone() {
117
+        $this->configuration = new Configuration($this->configPrefix,
118
+                                                    !is_null($this->configID));
119
+        $this->ldapConnectionRes = null;
120
+        $this->dontDestruct = true;
121
+    }
122
+
123
+    /**
124
+     * @param string $name
125
+     * @return bool|mixed|void
126
+     */
127
+    public function __get($name) {
128
+        if(!$this->configured) {
129
+            $this->readConfiguration();
130
+        }
131
+
132
+        if($name === 'hasPagedResultSupport') {
133
+            return $this->hasPagedResultSupport;
134
+        }
135
+
136
+        return $this->configuration->$name;
137
+    }
138
+
139
+    /**
140
+     * @param string $name
141
+     * @param mixed $value
142
+     */
143
+    public function __set($name, $value) {
144
+        $this->doNotValidate = false;
145
+        $before = $this->configuration->$name;
146
+        $this->configuration->$name = $value;
147
+        $after = $this->configuration->$name;
148
+        if($before !== $after) {
149
+            if ($this->configID !== '') {
150
+                $this->configuration->saveConfiguration();
151
+            }
152
+            $this->validateConfiguration();
153
+        }
154
+    }
155
+
156
+    /**
157
+     * sets whether the result of the configuration validation shall
158
+     * be ignored when establishing the connection. Used by the Wizard
159
+     * in early configuration state.
160
+     * @param bool $state
161
+     */
162
+    public function setIgnoreValidation($state) {
163
+        $this->ignoreValidation = (bool)$state;
164
+    }
165
+
166
+    /**
167
+     * initializes the LDAP backend
168
+     * @param bool $force read the config settings no matter what
169
+     */
170
+    public function init($force = false) {
171
+        $this->readConfiguration($force);
172
+        $this->establishConnection();
173
+    }
174
+
175
+    /**
176
+     * Returns the LDAP handler
177
+     */
178
+    public function getConnectionResource() {
179
+        if(!$this->ldapConnectionRes) {
180
+            $this->init();
181
+        } else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
182
+            $this->ldapConnectionRes = null;
183
+            $this->establishConnection();
184
+        }
185
+        if(is_null($this->ldapConnectionRes)) {
186
+            \OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
187
+            throw new ServerNotAvailableException('Connection to LDAP server could not be established');
188
+        }
189
+        return $this->ldapConnectionRes;
190
+    }
191
+
192
+    /**
193
+     * resets the connection resource
194
+     */
195
+    public function resetConnectionResource() {
196
+        if(!is_null($this->ldapConnectionRes)) {
197
+            @$this->ldap->unbind($this->ldapConnectionRes);
198
+            $this->ldapConnectionRes = null;
199
+        }
200
+    }
201
+
202
+    /**
203
+     * @param string|null $key
204
+     * @return string
205
+     */
206
+    private function getCacheKey($key) {
207
+        $prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
208
+        if(is_null($key)) {
209
+            return $prefix;
210
+        }
211
+        return $prefix.md5($key);
212
+    }
213
+
214
+    /**
215
+     * @param string $key
216
+     * @return mixed|null
217
+     */
218
+    public function getFromCache($key) {
219
+        if(!$this->configured) {
220
+            $this->readConfiguration();
221
+        }
222
+        if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
223
+            return null;
224
+        }
225
+        $key = $this->getCacheKey($key);
226
+
227
+        return json_decode(base64_decode($this->cache->get($key)), true);
228
+    }
229
+
230
+    /**
231
+     * @param string $key
232
+     * @param mixed $value
233
+     *
234
+     * @return string
235
+     */
236
+    public function writeToCache($key, $value) {
237
+        if(!$this->configured) {
238
+            $this->readConfiguration();
239
+        }
240
+        if(is_null($this->cache)
241
+            || !$this->configuration->ldapCacheTTL
242
+            || !$this->configuration->ldapConfigurationActive) {
243
+            return null;
244
+        }
245
+        $key   = $this->getCacheKey($key);
246
+        $value = base64_encode(json_encode($value));
247
+        $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
248
+    }
249
+
250
+    public function clearCache() {
251
+        if(!is_null($this->cache)) {
252
+            $this->cache->clear($this->getCacheKey(null));
253
+        }
254
+    }
255
+
256
+    /**
257
+     * Caches the general LDAP configuration.
258
+     * @param bool $force optional. true, if the re-read should be forced. defaults
259
+     * to false.
260
+     * @return null
261
+     */
262
+    private function readConfiguration($force = false) {
263
+        if((!$this->configured || $force) && !is_null($this->configID)) {
264
+            $this->configuration->readConfiguration();
265
+            $this->configured = $this->validateConfiguration();
266
+        }
267
+    }
268
+
269
+    /**
270
+     * set LDAP configuration with values delivered by an array, not read from configuration
271
+     * @param array $config array that holds the config parameters in an associated array
272
+     * @param array &$setParameters optional; array where the set fields will be given to
273
+     * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
274
+     */
275
+    public function setConfiguration($config, &$setParameters = null) {
276
+        if(is_null($setParameters)) {
277
+            $setParameters = array();
278
+        }
279
+        $this->doNotValidate = false;
280
+        $this->configuration->setConfiguration($config, $setParameters);
281
+        if(count($setParameters) > 0) {
282
+            $this->configured = $this->validateConfiguration();
283
+        }
284
+
285
+
286
+        return $this->configured;
287
+    }
288
+
289
+    /**
290
+     * saves the current Configuration in the database and empties the
291
+     * cache
292
+     * @return null
293
+     */
294
+    public function saveConfiguration() {
295
+        $this->configuration->saveConfiguration();
296
+        $this->clearCache();
297
+    }
298
+
299
+    /**
300
+     * get the current LDAP configuration
301
+     * @return array
302
+     */
303
+    public function getConfiguration() {
304
+        $this->readConfiguration();
305
+        $config = $this->configuration->getConfiguration();
306
+        $cta = $this->configuration->getConfigTranslationArray();
307
+        $result = array();
308
+        foreach($cta as $dbkey => $configkey) {
309
+            switch($configkey) {
310
+                case 'homeFolderNamingRule':
311
+                    if(strpos($config[$configkey], 'attr:') === 0) {
312
+                        $result[$dbkey] = substr($config[$configkey], 5);
313
+                    } else {
314
+                        $result[$dbkey] = '';
315
+                    }
316
+                    break;
317
+                case 'ldapBase':
318
+                case 'ldapBaseUsers':
319
+                case 'ldapBaseGroups':
320
+                case 'ldapAttributesForUserSearch':
321
+                case 'ldapAttributesForGroupSearch':
322
+                    if(is_array($config[$configkey])) {
323
+                        $result[$dbkey] = implode("\n", $config[$configkey]);
324
+                        break;
325
+                    } //else follows default
326
+                default:
327
+                    $result[$dbkey] = $config[$configkey];
328
+            }
329
+        }
330
+        return $result;
331
+    }
332
+
333
+    private function doSoftValidation() {
334
+        //if User or Group Base are not set, take over Base DN setting
335
+        foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
336
+            $val = $this->configuration->$keyBase;
337
+            if(empty($val)) {
338
+                $this->configuration->$keyBase = $this->configuration->ldapBase;
339
+            }
340
+        }
341
+
342
+        foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
343
+                        'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
344
+                as $expertSetting => $effectiveSetting) {
345
+            $uuidOverride = $this->configuration->$expertSetting;
346
+            if(!empty($uuidOverride)) {
347
+                $this->configuration->$effectiveSetting = $uuidOverride;
348
+            } else {
349
+                $uuidAttributes = array('auto', 'entryuuid', 'nsuniqueid',
350
+                                        'objectguid', 'guid', 'ipauniqueid');
351
+                if(!in_array($this->configuration->$effectiveSetting,
352
+                            $uuidAttributes)
353
+                    && (!is_null($this->configID))) {
354
+                    $this->configuration->$effectiveSetting = 'auto';
355
+                    $this->configuration->saveConfiguration();
356
+                    \OCP\Util::writeLog('user_ldap',
357
+                                        'Illegal value for the '.
358
+                                        $effectiveSetting.', '.'reset to '.
359
+                                        'autodetect.', \OCP\Util::INFO);
360
+                }
361
+
362
+            }
363
+        }
364
+
365
+        $backupPort = intval($this->configuration->ldapBackupPort);
366
+        if ($backupPort <= 0) {
367
+            $this->configuration->backupPort = $this->configuration->ldapPort;
368
+        }
369
+
370
+        //make sure empty search attributes are saved as simple, empty array
371
+        $saKeys = array('ldapAttributesForUserSearch',
372
+                        'ldapAttributesForGroupSearch');
373
+        foreach($saKeys as $key) {
374
+            $val = $this->configuration->$key;
375
+            if(is_array($val) && count($val) === 1 && empty($val[0])) {
376
+                $this->configuration->$key = array();
377
+            }
378
+        }
379
+
380
+        if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
381
+            && $this->configuration->ldapTLS) {
382
+            $this->configuration->ldapTLS = false;
383
+            \OCP\Util::writeLog('user_ldap',
384
+                                'LDAPS (already using secure connection) and '.
385
+                                'TLS do not work together. Switched off TLS.',
386
+                                \OCP\Util::INFO);
387
+        }
388
+    }
389
+
390
+    /**
391
+     * @return bool
392
+     */
393
+    private function doCriticalValidation() {
394
+        $configurationOK = true;
395
+        $errorStr = 'Configuration Error (prefix '.
396
+                    strval($this->configPrefix).'): ';
397
+
398
+        //options that shall not be empty
399
+        $options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
400
+                            'ldapGroupDisplayName', 'ldapLoginFilter');
401
+        foreach($options as $key) {
402
+            $val = $this->configuration->$key;
403
+            if(empty($val)) {
404
+                switch($key) {
405
+                    case 'ldapHost':
406
+                        $subj = 'LDAP Host';
407
+                        break;
408
+                    case 'ldapPort':
409
+                        $subj = 'LDAP Port';
410
+                        break;
411
+                    case 'ldapUserDisplayName':
412
+                        $subj = 'LDAP User Display Name';
413
+                        break;
414
+                    case 'ldapGroupDisplayName':
415
+                        $subj = 'LDAP Group Display Name';
416
+                        break;
417
+                    case 'ldapLoginFilter':
418
+                        $subj = 'LDAP Login Filter';
419
+                        break;
420
+                    default:
421
+                        $subj = $key;
422
+                        break;
423
+                }
424
+                $configurationOK = false;
425
+                \OCP\Util::writeLog('user_ldap',
426
+                                    $errorStr.'No '.$subj.' given!',
427
+                                    \OCP\Util::WARN);
428
+            }
429
+        }
430
+
431
+        //combinations
432
+        $agent = $this->configuration->ldapAgentName;
433
+        $pwd = $this->configuration->ldapAgentPassword;
434
+        if (
435
+            ($agent === ''  && $pwd !== '')
436
+            || ($agent !== '' && $pwd === '')
437
+        ) {
438
+            \OCP\Util::writeLog('user_ldap',
439
+                                $errorStr.'either no password is given for the'.
440
+                                'user agent or a password is given, but not an'.
441
+                                'LDAP agent.',
442
+                \OCP\Util::WARN);
443
+            $configurationOK = false;
444
+        }
445
+
446
+        $base = $this->configuration->ldapBase;
447
+        $baseUsers = $this->configuration->ldapBaseUsers;
448
+        $baseGroups = $this->configuration->ldapBaseGroups;
449
+
450
+        if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
451
+            \OCP\Util::writeLog('user_ldap',
452
+                                $errorStr.'Not a single Base DN given.',
453
+                                \OCP\Util::WARN);
454
+            $configurationOK = false;
455
+        }
456
+
457
+        if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
458
+            === false) {
459
+            \OCP\Util::writeLog('user_ldap',
460
+                                $errorStr.'login filter does not contain %uid '.
461
+                                'place holder.',
462
+                                \OCP\Util::WARN);
463
+            $configurationOK = false;
464
+        }
465
+
466
+        return $configurationOK;
467
+    }
468
+
469
+    /**
470
+     * Validates the user specified configuration
471
+     * @return bool true if configuration seems OK, false otherwise
472
+     */
473
+    private function validateConfiguration() {
474
+
475
+        if($this->doNotValidate) {
476
+            //don't do a validation if it is a new configuration with pure
477
+            //default values. Will be allowed on changes via __set or
478
+            //setConfiguration
479
+            return false;
480
+        }
481
+
482
+        // first step: "soft" checks: settings that are not really
483
+        // necessary, but advisable. If left empty, give an info message
484
+        $this->doSoftValidation();
485
+
486
+        //second step: critical checks. If left empty or filled wrong, mark as
487
+        //not configured and give a warning.
488
+        return $this->doCriticalValidation();
489
+    }
490
+
491
+
492
+    /**
493
+     * Connects and Binds to LDAP
494
+     */
495
+    private function establishConnection() {
496
+        if(!$this->configuration->ldapConfigurationActive) {
497
+            return null;
498
+        }
499
+        static $phpLDAPinstalled = true;
500
+        if(!$phpLDAPinstalled) {
501
+            return false;
502
+        }
503
+        if(!$this->ignoreValidation && !$this->configured) {
504
+            \OCP\Util::writeLog('user_ldap',
505
+                                'Configuration is invalid, cannot connect',
506
+                                \OCP\Util::WARN);
507
+            return false;
508
+        }
509
+        if(!$this->ldapConnectionRes) {
510
+            if(!$this->ldap->areLDAPFunctionsAvailable()) {
511
+                $phpLDAPinstalled = false;
512
+                \OCP\Util::writeLog('user_ldap',
513
+                                    'function ldap_connect is not available. Make '.
514
+                                    'sure that the PHP ldap module is installed.',
515
+                                    \OCP\Util::ERROR);
516
+
517
+                return false;
518
+            }
519
+            if($this->configuration->turnOffCertCheck) {
520
+                if(putenv('LDAPTLS_REQCERT=never')) {
521
+                    \OCP\Util::writeLog('user_ldap',
522
+                        'Turned off SSL certificate validation successfully.',
523
+                        \OCP\Util::DEBUG);
524
+                } else {
525
+                    \OCP\Util::writeLog('user_ldap',
526
+                                        'Could not turn off SSL certificate validation.',
527
+                                        \OCP\Util::WARN);
528
+                }
529
+            }
530
+
531
+            $bindStatus = false;
532
+            $error = -1;
533
+            try {
534
+                if (!$this->configuration->ldapOverrideMainServer
535
+                    && !$this->getFromCache('overrideMainServer')
536
+                ) {
537
+                    $this->doConnect($this->configuration->ldapHost,
538
+                        $this->configuration->ldapPort);
539
+                    $bindStatus = $this->bind();
540
+                    $error = $this->ldap->isResource($this->ldapConnectionRes) ?
541
+                        $this->ldap->errno($this->ldapConnectionRes) : -1;
542
+                }
543
+                if($bindStatus === true) {
544
+                    return $bindStatus;
545
+                }
546
+            } catch (\OC\ServerNotAvailableException $e) {
547
+                if(trim($this->configuration->ldapBackupHost) === "") {
548
+                    throw $e;
549
+                }
550
+            }
551
+
552
+            //if LDAP server is not reachable, try the Backup (Replica!) Server
553
+            if(    $error !== 0
554
+                || $this->configuration->ldapOverrideMainServer
555
+                || $this->getFromCache('overrideMainServer'))
556
+            {
557
+                $this->doConnect($this->configuration->ldapBackupHost,
558
+                                    $this->configuration->ldapBackupPort);
559
+                $bindStatus = $this->bind();
560
+                if($bindStatus && $error === -1 && !$this->getFromCache('overrideMainServer')) {
561
+                    //when bind to backup server succeeded and failed to main server,
562
+                    //skip contacting him until next cache refresh
563
+                    $this->writeToCache('overrideMainServer', true);
564
+                }
565
+            }
566
+            return $bindStatus;
567
+        }
568
+        return null;
569
+    }
570
+
571
+    /**
572
+     * @param string $host
573
+     * @param string $port
574
+     * @return bool
575
+     * @throws \OC\ServerNotAvailableException
576
+     */
577
+    private function doConnect($host, $port) {
578
+        if ($host === '') {
579
+            return false;
580
+        }
581
+        $this->ldapConnectionRes = $this->ldap->connect($host, $port);
582
+        if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
583
+            if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
584
+                if($this->configuration->ldapTLS) {
585
+                    $this->ldap->startTls($this->ldapConnectionRes);
586
+                }
587
+            }
588
+        } else {
589
+            throw new \OC\ServerNotAvailableException('Could not set required LDAP Protocol version.');
590
+        }
591
+        return true;
592
+    }
593
+
594
+    /**
595
+     * Binds to LDAP
596
+     */
597
+    public function bind() {
598
+        static $getConnectionResourceAttempt = false;
599
+        if(!$this->configuration->ldapConfigurationActive) {
600
+            return false;
601
+        }
602
+        if($getConnectionResourceAttempt) {
603
+            $getConnectionResourceAttempt = false;
604
+            return false;
605
+        }
606
+        $getConnectionResourceAttempt = true;
607
+        $cr = $this->getConnectionResource();
608
+        $getConnectionResourceAttempt = false;
609
+        if(!$this->ldap->isResource($cr)) {
610
+            return false;
611
+        }
612
+        $ldapLogin = @$this->ldap->bind($cr,
613
+                                        $this->configuration->ldapAgentName,
614
+                                        $this->configuration->ldapAgentPassword);
615
+        if(!$ldapLogin) {
616
+            \OCP\Util::writeLog('user_ldap',
617
+                'Bind failed: ' . $this->ldap->errno($cr) . ': ' . $this->ldap->error($cr),
618
+                \OCP\Util::WARN);
619
+            $this->ldapConnectionRes = null;
620
+            return false;
621
+        }
622
+        return true;
623
+    }
624 624
 
625 625
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Configuration.php 1 patch
Indentation   +460 added lines, -460 removed lines patch added patch discarded remove patch
@@ -36,489 +36,489 @@
 block discarded – undo
36 36
  */
37 37
 class Configuration {
38 38
 
39
-	protected $configPrefix = null;
40
-	protected $configRead = false;
39
+    protected $configPrefix = null;
40
+    protected $configRead = false;
41 41
 
42
-	//settings
43
-	protected $config = array(
44
-		'ldapHost' => null,
45
-		'ldapPort' => null,
46
-		'ldapBackupHost' => null,
47
-		'ldapBackupPort' => null,
48
-		'ldapBase' => null,
49
-		'ldapBaseUsers' => null,
50
-		'ldapBaseGroups' => null,
51
-		'ldapAgentName' => null,
52
-		'ldapAgentPassword' => null,
53
-		'ldapTLS' => null,
54
-		'turnOffCertCheck' => null,
55
-		'ldapIgnoreNamingRules' => null,
56
-		'ldapUserDisplayName' => null,
57
-		'ldapUserDisplayName2' => null,
58
-		'ldapGidNumber' => null,
59
-		'ldapUserFilterObjectclass' => null,
60
-		'ldapUserFilterGroups' => null,
61
-		'ldapUserFilter' => null,
62
-		'ldapUserFilterMode' => null,
63
-		'ldapGroupFilter' => null,
64
-		'ldapGroupFilterMode' => null,
65
-		'ldapGroupFilterObjectclass' => null,
66
-		'ldapGroupFilterGroups' => null,
67
-		'ldapGroupDisplayName' => null,
68
-		'ldapGroupMemberAssocAttr' => null,
69
-		'ldapLoginFilter' => null,
70
-		'ldapLoginFilterMode' => null,
71
-		'ldapLoginFilterEmail' => null,
72
-		'ldapLoginFilterUsername' => null,
73
-		'ldapLoginFilterAttributes' => null,
74
-		'ldapQuotaAttribute' => null,
75
-		'ldapQuotaDefault' => null,
76
-		'ldapEmailAttribute' => null,
77
-		'ldapCacheTTL' => null,
78
-		'ldapUuidUserAttribute' => 'auto',
79
-		'ldapUuidGroupAttribute' => 'auto',
80
-		'ldapOverrideMainServer' => false,
81
-		'ldapConfigurationActive' => false,
82
-		'ldapAttributesForUserSearch' => null,
83
-		'ldapAttributesForGroupSearch' => null,
84
-		'ldapExperiencedAdmin' => false,
85
-		'homeFolderNamingRule' => null,
86
-		'hasPagedResultSupport' => false,
87
-		'hasMemberOfFilterSupport' => false,
88
-		'useMemberOfToDetectMembership' => true,
89
-		'ldapExpertUsernameAttr' => null,
90
-		'ldapExpertUUIDUserAttr' => null,
91
-		'ldapExpertUUIDGroupAttr' => null,
92
-		'lastJpegPhotoLookup' => null,
93
-		'ldapNestedGroups' => false,
94
-		'ldapPagingSize' => null,
95
-		'turnOnPasswordChange' => false,
96
-		'ldapDynamicGroupMemberURL' => null,
97
-	);
42
+    //settings
43
+    protected $config = array(
44
+        'ldapHost' => null,
45
+        'ldapPort' => null,
46
+        'ldapBackupHost' => null,
47
+        'ldapBackupPort' => null,
48
+        'ldapBase' => null,
49
+        'ldapBaseUsers' => null,
50
+        'ldapBaseGroups' => null,
51
+        'ldapAgentName' => null,
52
+        'ldapAgentPassword' => null,
53
+        'ldapTLS' => null,
54
+        'turnOffCertCheck' => null,
55
+        'ldapIgnoreNamingRules' => null,
56
+        'ldapUserDisplayName' => null,
57
+        'ldapUserDisplayName2' => null,
58
+        'ldapGidNumber' => null,
59
+        'ldapUserFilterObjectclass' => null,
60
+        'ldapUserFilterGroups' => null,
61
+        'ldapUserFilter' => null,
62
+        'ldapUserFilterMode' => null,
63
+        'ldapGroupFilter' => null,
64
+        'ldapGroupFilterMode' => null,
65
+        'ldapGroupFilterObjectclass' => null,
66
+        'ldapGroupFilterGroups' => null,
67
+        'ldapGroupDisplayName' => null,
68
+        'ldapGroupMemberAssocAttr' => null,
69
+        'ldapLoginFilter' => null,
70
+        'ldapLoginFilterMode' => null,
71
+        'ldapLoginFilterEmail' => null,
72
+        'ldapLoginFilterUsername' => null,
73
+        'ldapLoginFilterAttributes' => null,
74
+        'ldapQuotaAttribute' => null,
75
+        'ldapQuotaDefault' => null,
76
+        'ldapEmailAttribute' => null,
77
+        'ldapCacheTTL' => null,
78
+        'ldapUuidUserAttribute' => 'auto',
79
+        'ldapUuidGroupAttribute' => 'auto',
80
+        'ldapOverrideMainServer' => false,
81
+        'ldapConfigurationActive' => false,
82
+        'ldapAttributesForUserSearch' => null,
83
+        'ldapAttributesForGroupSearch' => null,
84
+        'ldapExperiencedAdmin' => false,
85
+        'homeFolderNamingRule' => null,
86
+        'hasPagedResultSupport' => false,
87
+        'hasMemberOfFilterSupport' => false,
88
+        'useMemberOfToDetectMembership' => true,
89
+        'ldapExpertUsernameAttr' => null,
90
+        'ldapExpertUUIDUserAttr' => null,
91
+        'ldapExpertUUIDGroupAttr' => null,
92
+        'lastJpegPhotoLookup' => null,
93
+        'ldapNestedGroups' => false,
94
+        'ldapPagingSize' => null,
95
+        'turnOnPasswordChange' => false,
96
+        'ldapDynamicGroupMemberURL' => null,
97
+    );
98 98
 
99
-	/**
100
-	 * @param string $configPrefix
101
-	 * @param bool $autoRead
102
-	 */
103
-	public function __construct($configPrefix, $autoRead = true) {
104
-		$this->configPrefix = $configPrefix;
105
-		if($autoRead) {
106
-			$this->readConfiguration();
107
-		}
108
-	}
99
+    /**
100
+     * @param string $configPrefix
101
+     * @param bool $autoRead
102
+     */
103
+    public function __construct($configPrefix, $autoRead = true) {
104
+        $this->configPrefix = $configPrefix;
105
+        if($autoRead) {
106
+            $this->readConfiguration();
107
+        }
108
+    }
109 109
 
110
-	/**
111
-	 * @param string $name
112
-	 * @return mixed|null
113
-	 */
114
-	public function __get($name) {
115
-		if(isset($this->config[$name])) {
116
-			return $this->config[$name];
117
-		}
118
-		return null;
119
-	}
110
+    /**
111
+     * @param string $name
112
+     * @return mixed|null
113
+     */
114
+    public function __get($name) {
115
+        if(isset($this->config[$name])) {
116
+            return $this->config[$name];
117
+        }
118
+        return null;
119
+    }
120 120
 
121
-	/**
122
-	 * @param string $name
123
-	 * @param mixed $value
124
-	 */
125
-	public function __set($name, $value) {
126
-		$this->setConfiguration(array($name => $value));
127
-	}
121
+    /**
122
+     * @param string $name
123
+     * @param mixed $value
124
+     */
125
+    public function __set($name, $value) {
126
+        $this->setConfiguration(array($name => $value));
127
+    }
128 128
 
129
-	/**
130
-	 * @return array
131
-	 */
132
-	public function getConfiguration() {
133
-		return $this->config;
134
-	}
129
+    /**
130
+     * @return array
131
+     */
132
+    public function getConfiguration() {
133
+        return $this->config;
134
+    }
135 135
 
136
-	/**
137
-	 * set LDAP configuration with values delivered by an array, not read
138
-	 * from configuration. It does not save the configuration! To do so, you
139
-	 * must call saveConfiguration afterwards.
140
-	 * @param array $config array that holds the config parameters in an associated
141
-	 * array
142
-	 * @param array &$applied optional; array where the set fields will be given to
143
-	 * @return false|null
144
-	 */
145
-	public function setConfiguration($config, &$applied = null) {
146
-		if(!is_array($config)) {
147
-			return false;
148
-		}
136
+    /**
137
+     * set LDAP configuration with values delivered by an array, not read
138
+     * from configuration. It does not save the configuration! To do so, you
139
+     * must call saveConfiguration afterwards.
140
+     * @param array $config array that holds the config parameters in an associated
141
+     * array
142
+     * @param array &$applied optional; array where the set fields will be given to
143
+     * @return false|null
144
+     */
145
+    public function setConfiguration($config, &$applied = null) {
146
+        if(!is_array($config)) {
147
+            return false;
148
+        }
149 149
 
150
-		$cta = $this->getConfigTranslationArray();
151
-		foreach($config as $inputKey => $val) {
152
-			if(strpos($inputKey, '_') !== false && array_key_exists($inputKey, $cta)) {
153
-				$key = $cta[$inputKey];
154
-			} elseif(array_key_exists($inputKey, $this->config)) {
155
-				$key = $inputKey;
156
-			} else {
157
-				continue;
158
-			}
150
+        $cta = $this->getConfigTranslationArray();
151
+        foreach($config as $inputKey => $val) {
152
+            if(strpos($inputKey, '_') !== false && array_key_exists($inputKey, $cta)) {
153
+                $key = $cta[$inputKey];
154
+            } elseif(array_key_exists($inputKey, $this->config)) {
155
+                $key = $inputKey;
156
+            } else {
157
+                continue;
158
+            }
159 159
 
160
-			$setMethod = 'setValue';
161
-			switch($key) {
162
-				case 'ldapAgentPassword':
163
-					$setMethod = 'setRawValue';
164
-					break;
165
-				case 'homeFolderNamingRule':
166
-					$trimmedVal = trim($val);
167
-					if ($trimmedVal !== '' && strpos($val, 'attr:') === false) {
168
-						$val = 'attr:'.$trimmedVal;
169
-					}
170
-					break;
171
-				case 'ldapBase':
172
-				case 'ldapBaseUsers':
173
-				case 'ldapBaseGroups':
174
-				case 'ldapAttributesForUserSearch':
175
-				case 'ldapAttributesForGroupSearch':
176
-				case 'ldapUserFilterObjectclass':
177
-				case 'ldapUserFilterGroups':
178
-				case 'ldapGroupFilterObjectclass':
179
-				case 'ldapGroupFilterGroups':
180
-				case 'ldapLoginFilterAttributes':
181
-					$setMethod = 'setMultiLine';
182
-					break;
183
-			}
184
-			$this->$setMethod($key, $val);
185
-			if(is_array($applied)) {
186
-				$applied[] = $inputKey;
187
-			}
188
-		}
189
-		return null;
190
-	}
160
+            $setMethod = 'setValue';
161
+            switch($key) {
162
+                case 'ldapAgentPassword':
163
+                    $setMethod = 'setRawValue';
164
+                    break;
165
+                case 'homeFolderNamingRule':
166
+                    $trimmedVal = trim($val);
167
+                    if ($trimmedVal !== '' && strpos($val, 'attr:') === false) {
168
+                        $val = 'attr:'.$trimmedVal;
169
+                    }
170
+                    break;
171
+                case 'ldapBase':
172
+                case 'ldapBaseUsers':
173
+                case 'ldapBaseGroups':
174
+                case 'ldapAttributesForUserSearch':
175
+                case 'ldapAttributesForGroupSearch':
176
+                case 'ldapUserFilterObjectclass':
177
+                case 'ldapUserFilterGroups':
178
+                case 'ldapGroupFilterObjectclass':
179
+                case 'ldapGroupFilterGroups':
180
+                case 'ldapLoginFilterAttributes':
181
+                    $setMethod = 'setMultiLine';
182
+                    break;
183
+            }
184
+            $this->$setMethod($key, $val);
185
+            if(is_array($applied)) {
186
+                $applied[] = $inputKey;
187
+            }
188
+        }
189
+        return null;
190
+    }
191 191
 
192
-	public function readConfiguration() {
193
-		if(!$this->configRead && !is_null($this->configPrefix)) {
194
-			$cta = array_flip($this->getConfigTranslationArray());
195
-			foreach($this->config as $key => $val) {
196
-				if(!isset($cta[$key])) {
197
-					//some are determined
198
-					continue;
199
-				}
200
-				$dbKey = $cta[$key];
201
-				switch($key) {
202
-					case 'ldapBase':
203
-					case 'ldapBaseUsers':
204
-					case 'ldapBaseGroups':
205
-					case 'ldapAttributesForUserSearch':
206
-					case 'ldapAttributesForGroupSearch':
207
-					case 'ldapUserFilterObjectclass':
208
-					case 'ldapUserFilterGroups':
209
-					case 'ldapGroupFilterObjectclass':
210
-					case 'ldapGroupFilterGroups':
211
-					case 'ldapLoginFilterAttributes':
212
-						$readMethod = 'getMultiLine';
213
-						break;
214
-					case 'ldapIgnoreNamingRules':
215
-						$readMethod = 'getSystemValue';
216
-						$dbKey = $key;
217
-						break;
218
-					case 'ldapAgentPassword':
219
-						$readMethod = 'getPwd';
220
-						break;
221
-					case 'ldapUserDisplayName2':
222
-					case 'ldapGroupDisplayName':
223
-						$readMethod = 'getLcValue';
224
-						break;
225
-					case 'ldapUserDisplayName':
226
-					default:
227
-						// user display name does not lower case because
228
-						// we rely on an upper case N as indicator whether to
229
-						// auto-detect it or not. FIXME
230
-						$readMethod = 'getValue';
231
-						break;
232
-				}
233
-				$this->config[$key] = $this->$readMethod($dbKey);
234
-			}
235
-			$this->configRead = true;
236
-		}
237
-	}
192
+    public function readConfiguration() {
193
+        if(!$this->configRead && !is_null($this->configPrefix)) {
194
+            $cta = array_flip($this->getConfigTranslationArray());
195
+            foreach($this->config as $key => $val) {
196
+                if(!isset($cta[$key])) {
197
+                    //some are determined
198
+                    continue;
199
+                }
200
+                $dbKey = $cta[$key];
201
+                switch($key) {
202
+                    case 'ldapBase':
203
+                    case 'ldapBaseUsers':
204
+                    case 'ldapBaseGroups':
205
+                    case 'ldapAttributesForUserSearch':
206
+                    case 'ldapAttributesForGroupSearch':
207
+                    case 'ldapUserFilterObjectclass':
208
+                    case 'ldapUserFilterGroups':
209
+                    case 'ldapGroupFilterObjectclass':
210
+                    case 'ldapGroupFilterGroups':
211
+                    case 'ldapLoginFilterAttributes':
212
+                        $readMethod = 'getMultiLine';
213
+                        break;
214
+                    case 'ldapIgnoreNamingRules':
215
+                        $readMethod = 'getSystemValue';
216
+                        $dbKey = $key;
217
+                        break;
218
+                    case 'ldapAgentPassword':
219
+                        $readMethod = 'getPwd';
220
+                        break;
221
+                    case 'ldapUserDisplayName2':
222
+                    case 'ldapGroupDisplayName':
223
+                        $readMethod = 'getLcValue';
224
+                        break;
225
+                    case 'ldapUserDisplayName':
226
+                    default:
227
+                        // user display name does not lower case because
228
+                        // we rely on an upper case N as indicator whether to
229
+                        // auto-detect it or not. FIXME
230
+                        $readMethod = 'getValue';
231
+                        break;
232
+                }
233
+                $this->config[$key] = $this->$readMethod($dbKey);
234
+            }
235
+            $this->configRead = true;
236
+        }
237
+    }
238 238
 
239
-	/**
240
-	 * saves the current Configuration in the database
241
-	 */
242
-	public function saveConfiguration() {
243
-		$cta = array_flip($this->getConfigTranslationArray());
244
-		foreach($this->config as $key => $value) {
245
-			switch ($key) {
246
-				case 'ldapAgentPassword':
247
-					$value = base64_encode($value);
248
-					break;
249
-				case 'ldapBase':
250
-				case 'ldapBaseUsers':
251
-				case 'ldapBaseGroups':
252
-				case 'ldapAttributesForUserSearch':
253
-				case 'ldapAttributesForGroupSearch':
254
-				case 'ldapUserFilterObjectclass':
255
-				case 'ldapUserFilterGroups':
256
-				case 'ldapGroupFilterObjectclass':
257
-				case 'ldapGroupFilterGroups':
258
-				case 'ldapLoginFilterAttributes':
259
-					if(is_array($value)) {
260
-						$value = implode("\n", $value);
261
-					}
262
-					break;
263
-				//following options are not stored but detected, skip them
264
-				case 'ldapIgnoreNamingRules':
265
-				case 'hasPagedResultSupport':
266
-				case 'ldapUuidUserAttribute':
267
-				case 'ldapUuidGroupAttribute':
268
-					continue 2;
269
-			}
270
-			if(is_null($value)) {
271
-				$value = '';
272
-			}
273
-			$this->saveValue($cta[$key], $value);
274
-		}
275
-	}
239
+    /**
240
+     * saves the current Configuration in the database
241
+     */
242
+    public function saveConfiguration() {
243
+        $cta = array_flip($this->getConfigTranslationArray());
244
+        foreach($this->config as $key => $value) {
245
+            switch ($key) {
246
+                case 'ldapAgentPassword':
247
+                    $value = base64_encode($value);
248
+                    break;
249
+                case 'ldapBase':
250
+                case 'ldapBaseUsers':
251
+                case 'ldapBaseGroups':
252
+                case 'ldapAttributesForUserSearch':
253
+                case 'ldapAttributesForGroupSearch':
254
+                case 'ldapUserFilterObjectclass':
255
+                case 'ldapUserFilterGroups':
256
+                case 'ldapGroupFilterObjectclass':
257
+                case 'ldapGroupFilterGroups':
258
+                case 'ldapLoginFilterAttributes':
259
+                    if(is_array($value)) {
260
+                        $value = implode("\n", $value);
261
+                    }
262
+                    break;
263
+                //following options are not stored but detected, skip them
264
+                case 'ldapIgnoreNamingRules':
265
+                case 'hasPagedResultSupport':
266
+                case 'ldapUuidUserAttribute':
267
+                case 'ldapUuidGroupAttribute':
268
+                    continue 2;
269
+            }
270
+            if(is_null($value)) {
271
+                $value = '';
272
+            }
273
+            $this->saveValue($cta[$key], $value);
274
+        }
275
+    }
276 276
 
277
-	/**
278
-	 * @param string $varName
279
-	 * @return array|string
280
-	 */
281
-	protected function getMultiLine($varName) {
282
-		$value = $this->getValue($varName);
283
-		if(empty($value)) {
284
-			$value = '';
285
-		} else {
286
-			$value = preg_split('/\r\n|\r|\n/', $value);
287
-		}
277
+    /**
278
+     * @param string $varName
279
+     * @return array|string
280
+     */
281
+    protected function getMultiLine($varName) {
282
+        $value = $this->getValue($varName);
283
+        if(empty($value)) {
284
+            $value = '';
285
+        } else {
286
+            $value = preg_split('/\r\n|\r|\n/', $value);
287
+        }
288 288
 
289
-		return $value;
290
-	}
289
+        return $value;
290
+    }
291 291
 
292
-	/**
293
-	 * Sets multi-line values as arrays
294
-	 * 
295
-	 * @param string $varName name of config-key
296
-	 * @param array|string $value to set
297
-	 */
298
-	protected function setMultiLine($varName, $value) {
299
-		if(empty($value)) {
300
-			$value = '';
301
-		} else if (!is_array($value)) {
302
-			$value = preg_split('/\r\n|\r|\n|;/', $value);
303
-			if($value === false) {
304
-				$value = '';
305
-			}
306
-		}
292
+    /**
293
+     * Sets multi-line values as arrays
294
+     * 
295
+     * @param string $varName name of config-key
296
+     * @param array|string $value to set
297
+     */
298
+    protected function setMultiLine($varName, $value) {
299
+        if(empty($value)) {
300
+            $value = '';
301
+        } else if (!is_array($value)) {
302
+            $value = preg_split('/\r\n|\r|\n|;/', $value);
303
+            if($value === false) {
304
+                $value = '';
305
+            }
306
+        }
307 307
 
308
-		if(!is_array($value)) {
309
-			$finalValue = trim($value);
310
-		} else {
311
-			$finalValue = [];
312
-			foreach($value as $key => $val) {
313
-				if(is_string($val)) {
314
-					$val = trim($val);
315
-					if ($val !== '') {
316
-						//accidental line breaks are not wanted and can cause
317
-						// odd behaviour. Thus, away with them.
318
-						$finalValue[] = $val;
319
-					}
320
-				} else {
321
-					$finalValue[] = $val;
322
-				}
323
-			}
324
-		}
308
+        if(!is_array($value)) {
309
+            $finalValue = trim($value);
310
+        } else {
311
+            $finalValue = [];
312
+            foreach($value as $key => $val) {
313
+                if(is_string($val)) {
314
+                    $val = trim($val);
315
+                    if ($val !== '') {
316
+                        //accidental line breaks are not wanted and can cause
317
+                        // odd behaviour. Thus, away with them.
318
+                        $finalValue[] = $val;
319
+                    }
320
+                } else {
321
+                    $finalValue[] = $val;
322
+                }
323
+            }
324
+        }
325 325
 
326
-		$this->setRawValue($varName, $finalValue);
327
-	}
326
+        $this->setRawValue($varName, $finalValue);
327
+    }
328 328
 
329
-	/**
330
-	 * @param string $varName
331
-	 * @return string
332
-	 */
333
-	protected function getPwd($varName) {
334
-		return base64_decode($this->getValue($varName));
335
-	}
329
+    /**
330
+     * @param string $varName
331
+     * @return string
332
+     */
333
+    protected function getPwd($varName) {
334
+        return base64_decode($this->getValue($varName));
335
+    }
336 336
 
337
-	/**
338
-	 * @param string $varName
339
-	 * @return string
340
-	 */
341
-	protected function getLcValue($varName) {
342
-		return mb_strtolower($this->getValue($varName), 'UTF-8');
343
-	}
337
+    /**
338
+     * @param string $varName
339
+     * @return string
340
+     */
341
+    protected function getLcValue($varName) {
342
+        return mb_strtolower($this->getValue($varName), 'UTF-8');
343
+    }
344 344
 
345
-	/**
346
-	 * @param string $varName
347
-	 * @return string
348
-	 */
349
-	protected function getSystemValue($varName) {
350
-		//FIXME: if another system value is added, softcode the default value
351
-		return \OCP\Config::getSystemValue($varName, false);
352
-	}
345
+    /**
346
+     * @param string $varName
347
+     * @return string
348
+     */
349
+    protected function getSystemValue($varName) {
350
+        //FIXME: if another system value is added, softcode the default value
351
+        return \OCP\Config::getSystemValue($varName, false);
352
+    }
353 353
 
354
-	/**
355
-	 * @param string $varName
356
-	 * @return string
357
-	 */
358
-	protected function getValue($varName) {
359
-		static $defaults;
360
-		if(is_null($defaults)) {
361
-			$defaults = $this->getDefaults();
362
-		}
363
-		return \OCP\Config::getAppValue('user_ldap',
364
-										$this->configPrefix.$varName,
365
-										$defaults[$varName]);
366
-	}
354
+    /**
355
+     * @param string $varName
356
+     * @return string
357
+     */
358
+    protected function getValue($varName) {
359
+        static $defaults;
360
+        if(is_null($defaults)) {
361
+            $defaults = $this->getDefaults();
362
+        }
363
+        return \OCP\Config::getAppValue('user_ldap',
364
+                                        $this->configPrefix.$varName,
365
+                                        $defaults[$varName]);
366
+    }
367 367
 
368
-	/**
369
-	 * Sets a scalar value.
370
-	 * 
371
-	 * @param string $varName name of config key
372
-	 * @param mixed $value to set
373
-	 */
374
-	protected function setValue($varName, $value) {
375
-		if(is_string($value)) {
376
-			$value = trim($value);
377
-		}
378
-		$this->config[$varName] = $value;
379
-	}
368
+    /**
369
+     * Sets a scalar value.
370
+     * 
371
+     * @param string $varName name of config key
372
+     * @param mixed $value to set
373
+     */
374
+    protected function setValue($varName, $value) {
375
+        if(is_string($value)) {
376
+            $value = trim($value);
377
+        }
378
+        $this->config[$varName] = $value;
379
+    }
380 380
 
381
-	/**
382
-	 * Sets a scalar value without trimming.
383
-	 *
384
-	 * @param string $varName name of config key
385
-	 * @param mixed $value to set
386
-	 */
387
-	protected function setRawValue($varName, $value) {
388
-		$this->config[$varName] = $value;
389
-	}
381
+    /**
382
+     * Sets a scalar value without trimming.
383
+     *
384
+     * @param string $varName name of config key
385
+     * @param mixed $value to set
386
+     */
387
+    protected function setRawValue($varName, $value) {
388
+        $this->config[$varName] = $value;
389
+    }
390 390
 
391
-	/**
392
-	 * @param string $varName
393
-	 * @param string $value
394
-	 * @return bool
395
-	 */
396
-	protected function saveValue($varName, $value) {
397
-		\OC::$server->getConfig()->setAppValue(
398
-			'user_ldap',
399
-			$this->configPrefix.$varName,
400
-			$value
401
-		);
402
-		return true;
403
-	}
391
+    /**
392
+     * @param string $varName
393
+     * @param string $value
394
+     * @return bool
395
+     */
396
+    protected function saveValue($varName, $value) {
397
+        \OC::$server->getConfig()->setAppValue(
398
+            'user_ldap',
399
+            $this->configPrefix.$varName,
400
+            $value
401
+        );
402
+        return true;
403
+    }
404 404
 
405
-	/**
406
-	 * @return array an associative array with the default values. Keys are correspond
407
-	 * to config-value entries in the database table
408
-	 */
409
-	public function getDefaults() {
410
-		return array(
411
-			'ldap_host'                         => '',
412
-			'ldap_port'                         => '',
413
-			'ldap_backup_host'                  => '',
414
-			'ldap_backup_port'                  => '',
415
-			'ldap_override_main_server'         => '',
416
-			'ldap_dn'                           => '',
417
-			'ldap_agent_password'               => '',
418
-			'ldap_base'                         => '',
419
-			'ldap_base_users'                   => '',
420
-			'ldap_base_groups'                  => '',
421
-			'ldap_userlist_filter'              => '',
422
-			'ldap_user_filter_mode'             => 0,
423
-			'ldap_userfilter_objectclass'       => '',
424
-			'ldap_userfilter_groups'            => '',
425
-			'ldap_login_filter'                 => '',
426
-			'ldap_login_filter_mode'            => 0,
427
-			'ldap_loginfilter_email'            => 0,
428
-			'ldap_loginfilter_username'         => 1,
429
-			'ldap_loginfilter_attributes'       => '',
430
-			'ldap_group_filter'                 => '',
431
-			'ldap_group_filter_mode'            => 0,
432
-			'ldap_groupfilter_objectclass'      => '',
433
-			'ldap_groupfilter_groups'           => '',
434
-			'ldap_gid_number'                   => 'gidNumber',
435
-			'ldap_display_name'                 => 'displayName',
436
-			'ldap_user_display_name_2'			=> '',
437
-			'ldap_group_display_name'           => 'cn',
438
-			'ldap_tls'                          => 0,
439
-			'ldap_quota_def'                    => '',
440
-			'ldap_quota_attr'                   => '',
441
-			'ldap_email_attr'                   => '',
442
-			'ldap_group_member_assoc_attribute' => 'uniqueMember',
443
-			'ldap_cache_ttl'                    => 600,
444
-			'ldap_uuid_user_attribute'          => 'auto',
445
-			'ldap_uuid_group_attribute'         => 'auto',
446
-			'home_folder_naming_rule'           => '',
447
-			'ldap_turn_off_cert_check'          => 0,
448
-			'ldap_configuration_active'         => 0,
449
-			'ldap_attributes_for_user_search'   => '',
450
-			'ldap_attributes_for_group_search'  => '',
451
-			'ldap_expert_username_attr'         => '',
452
-			'ldap_expert_uuid_user_attr'        => '',
453
-			'ldap_expert_uuid_group_attr'       => '',
454
-			'has_memberof_filter_support'       => 0,
455
-			'use_memberof_to_detect_membership' => 1,
456
-			'last_jpegPhoto_lookup'             => 0,
457
-			'ldap_nested_groups'                => 0,
458
-			'ldap_paging_size'                  => 500,
459
-			'ldap_turn_on_pwd_change'           => 0,
460
-			'ldap_experienced_admin'            => 0,
461
-			'ldap_dynamic_group_member_url'     => '',
462
-		);
463
-	}
405
+    /**
406
+     * @return array an associative array with the default values. Keys are correspond
407
+     * to config-value entries in the database table
408
+     */
409
+    public function getDefaults() {
410
+        return array(
411
+            'ldap_host'                         => '',
412
+            'ldap_port'                         => '',
413
+            'ldap_backup_host'                  => '',
414
+            'ldap_backup_port'                  => '',
415
+            'ldap_override_main_server'         => '',
416
+            'ldap_dn'                           => '',
417
+            'ldap_agent_password'               => '',
418
+            'ldap_base'                         => '',
419
+            'ldap_base_users'                   => '',
420
+            'ldap_base_groups'                  => '',
421
+            'ldap_userlist_filter'              => '',
422
+            'ldap_user_filter_mode'             => 0,
423
+            'ldap_userfilter_objectclass'       => '',
424
+            'ldap_userfilter_groups'            => '',
425
+            'ldap_login_filter'                 => '',
426
+            'ldap_login_filter_mode'            => 0,
427
+            'ldap_loginfilter_email'            => 0,
428
+            'ldap_loginfilter_username'         => 1,
429
+            'ldap_loginfilter_attributes'       => '',
430
+            'ldap_group_filter'                 => '',
431
+            'ldap_group_filter_mode'            => 0,
432
+            'ldap_groupfilter_objectclass'      => '',
433
+            'ldap_groupfilter_groups'           => '',
434
+            'ldap_gid_number'                   => 'gidNumber',
435
+            'ldap_display_name'                 => 'displayName',
436
+            'ldap_user_display_name_2'			=> '',
437
+            'ldap_group_display_name'           => 'cn',
438
+            'ldap_tls'                          => 0,
439
+            'ldap_quota_def'                    => '',
440
+            'ldap_quota_attr'                   => '',
441
+            'ldap_email_attr'                   => '',
442
+            'ldap_group_member_assoc_attribute' => 'uniqueMember',
443
+            'ldap_cache_ttl'                    => 600,
444
+            'ldap_uuid_user_attribute'          => 'auto',
445
+            'ldap_uuid_group_attribute'         => 'auto',
446
+            'home_folder_naming_rule'           => '',
447
+            'ldap_turn_off_cert_check'          => 0,
448
+            'ldap_configuration_active'         => 0,
449
+            'ldap_attributes_for_user_search'   => '',
450
+            'ldap_attributes_for_group_search'  => '',
451
+            'ldap_expert_username_attr'         => '',
452
+            'ldap_expert_uuid_user_attr'        => '',
453
+            'ldap_expert_uuid_group_attr'       => '',
454
+            'has_memberof_filter_support'       => 0,
455
+            'use_memberof_to_detect_membership' => 1,
456
+            'last_jpegPhoto_lookup'             => 0,
457
+            'ldap_nested_groups'                => 0,
458
+            'ldap_paging_size'                  => 500,
459
+            'ldap_turn_on_pwd_change'           => 0,
460
+            'ldap_experienced_admin'            => 0,
461
+            'ldap_dynamic_group_member_url'     => '',
462
+        );
463
+    }
464 464
 
465
-	/**
466
-	 * @return array that maps internal variable names to database fields
467
-	 */
468
-	public function getConfigTranslationArray() {
469
-		//TODO: merge them into one representation
470
-		static $array = array(
471
-			'ldap_host'                         => 'ldapHost',
472
-			'ldap_port'                         => 'ldapPort',
473
-			'ldap_backup_host'                  => 'ldapBackupHost',
474
-			'ldap_backup_port'                  => 'ldapBackupPort',
475
-			'ldap_override_main_server'         => 'ldapOverrideMainServer',
476
-			'ldap_dn'                           => 'ldapAgentName',
477
-			'ldap_agent_password'               => 'ldapAgentPassword',
478
-			'ldap_base'                         => 'ldapBase',
479
-			'ldap_base_users'                   => 'ldapBaseUsers',
480
-			'ldap_base_groups'                  => 'ldapBaseGroups',
481
-			'ldap_userfilter_objectclass'       => 'ldapUserFilterObjectclass',
482
-			'ldap_userfilter_groups'            => 'ldapUserFilterGroups',
483
-			'ldap_userlist_filter'              => 'ldapUserFilter',
484
-			'ldap_user_filter_mode'             => 'ldapUserFilterMode',
485
-			'ldap_login_filter'                 => 'ldapLoginFilter',
486
-			'ldap_login_filter_mode'            => 'ldapLoginFilterMode',
487
-			'ldap_loginfilter_email'            => 'ldapLoginFilterEmail',
488
-			'ldap_loginfilter_username'         => 'ldapLoginFilterUsername',
489
-			'ldap_loginfilter_attributes'       => 'ldapLoginFilterAttributes',
490
-			'ldap_group_filter'                 => 'ldapGroupFilter',
491
-			'ldap_group_filter_mode'            => 'ldapGroupFilterMode',
492
-			'ldap_groupfilter_objectclass'      => 'ldapGroupFilterObjectclass',
493
-			'ldap_groupfilter_groups'           => 'ldapGroupFilterGroups',
494
-			'ldap_gid_number'                   => 'ldapGidNumber',
495
-			'ldap_display_name'                 => 'ldapUserDisplayName',
496
-			'ldap_user_display_name_2'			=> 'ldapUserDisplayName2',
497
-			'ldap_group_display_name'           => 'ldapGroupDisplayName',
498
-			'ldap_tls'                          => 'ldapTLS',
499
-			'ldap_quota_def'                    => 'ldapQuotaDefault',
500
-			'ldap_quota_attr'                   => 'ldapQuotaAttribute',
501
-			'ldap_email_attr'                   => 'ldapEmailAttribute',
502
-			'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
503
-			'ldap_cache_ttl'                    => 'ldapCacheTTL',
504
-			'home_folder_naming_rule'           => 'homeFolderNamingRule',
505
-			'ldap_turn_off_cert_check'          => 'turnOffCertCheck',
506
-			'ldap_configuration_active'         => 'ldapConfigurationActive',
507
-			'ldap_attributes_for_user_search'   => 'ldapAttributesForUserSearch',
508
-			'ldap_attributes_for_group_search'  => 'ldapAttributesForGroupSearch',
509
-			'ldap_expert_username_attr'         => 'ldapExpertUsernameAttr',
510
-			'ldap_expert_uuid_user_attr'        => 'ldapExpertUUIDUserAttr',
511
-			'ldap_expert_uuid_group_attr'       => 'ldapExpertUUIDGroupAttr',
512
-			'has_memberof_filter_support'       => 'hasMemberOfFilterSupport',
513
-			'use_memberof_to_detect_membership' => 'useMemberOfToDetectMembership',
514
-			'last_jpegPhoto_lookup'             => 'lastJpegPhotoLookup',
515
-			'ldap_nested_groups'                => 'ldapNestedGroups',
516
-			'ldap_paging_size'                  => 'ldapPagingSize',
517
-			'ldap_turn_on_pwd_change'           => 'turnOnPasswordChange',
518
-			'ldap_experienced_admin'            => 'ldapExperiencedAdmin',
519
-			'ldap_dynamic_group_member_url'     => 'ldapDynamicGroupMemberURL',
520
-		);
521
-		return $array;
522
-	}
465
+    /**
466
+     * @return array that maps internal variable names to database fields
467
+     */
468
+    public function getConfigTranslationArray() {
469
+        //TODO: merge them into one representation
470
+        static $array = array(
471
+            'ldap_host'                         => 'ldapHost',
472
+            'ldap_port'                         => 'ldapPort',
473
+            'ldap_backup_host'                  => 'ldapBackupHost',
474
+            'ldap_backup_port'                  => 'ldapBackupPort',
475
+            'ldap_override_main_server'         => 'ldapOverrideMainServer',
476
+            'ldap_dn'                           => 'ldapAgentName',
477
+            'ldap_agent_password'               => 'ldapAgentPassword',
478
+            'ldap_base'                         => 'ldapBase',
479
+            'ldap_base_users'                   => 'ldapBaseUsers',
480
+            'ldap_base_groups'                  => 'ldapBaseGroups',
481
+            'ldap_userfilter_objectclass'       => 'ldapUserFilterObjectclass',
482
+            'ldap_userfilter_groups'            => 'ldapUserFilterGroups',
483
+            'ldap_userlist_filter'              => 'ldapUserFilter',
484
+            'ldap_user_filter_mode'             => 'ldapUserFilterMode',
485
+            'ldap_login_filter'                 => 'ldapLoginFilter',
486
+            'ldap_login_filter_mode'            => 'ldapLoginFilterMode',
487
+            'ldap_loginfilter_email'            => 'ldapLoginFilterEmail',
488
+            'ldap_loginfilter_username'         => 'ldapLoginFilterUsername',
489
+            'ldap_loginfilter_attributes'       => 'ldapLoginFilterAttributes',
490
+            'ldap_group_filter'                 => 'ldapGroupFilter',
491
+            'ldap_group_filter_mode'            => 'ldapGroupFilterMode',
492
+            'ldap_groupfilter_objectclass'      => 'ldapGroupFilterObjectclass',
493
+            'ldap_groupfilter_groups'           => 'ldapGroupFilterGroups',
494
+            'ldap_gid_number'                   => 'ldapGidNumber',
495
+            'ldap_display_name'                 => 'ldapUserDisplayName',
496
+            'ldap_user_display_name_2'			=> 'ldapUserDisplayName2',
497
+            'ldap_group_display_name'           => 'ldapGroupDisplayName',
498
+            'ldap_tls'                          => 'ldapTLS',
499
+            'ldap_quota_def'                    => 'ldapQuotaDefault',
500
+            'ldap_quota_attr'                   => 'ldapQuotaAttribute',
501
+            'ldap_email_attr'                   => 'ldapEmailAttribute',
502
+            'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
503
+            'ldap_cache_ttl'                    => 'ldapCacheTTL',
504
+            'home_folder_naming_rule'           => 'homeFolderNamingRule',
505
+            'ldap_turn_off_cert_check'          => 'turnOffCertCheck',
506
+            'ldap_configuration_active'         => 'ldapConfigurationActive',
507
+            'ldap_attributes_for_user_search'   => 'ldapAttributesForUserSearch',
508
+            'ldap_attributes_for_group_search'  => 'ldapAttributesForGroupSearch',
509
+            'ldap_expert_username_attr'         => 'ldapExpertUsernameAttr',
510
+            'ldap_expert_uuid_user_attr'        => 'ldapExpertUUIDUserAttr',
511
+            'ldap_expert_uuid_group_attr'       => 'ldapExpertUUIDGroupAttr',
512
+            'has_memberof_filter_support'       => 'hasMemberOfFilterSupport',
513
+            'use_memberof_to_detect_membership' => 'useMemberOfToDetectMembership',
514
+            'last_jpegPhoto_lookup'             => 'lastJpegPhotoLookup',
515
+            'ldap_nested_groups'                => 'ldapNestedGroups',
516
+            'ldap_paging_size'                  => 'ldapPagingSize',
517
+            'ldap_turn_on_pwd_change'           => 'turnOnPasswordChange',
518
+            'ldap_experienced_admin'            => 'ldapExperiencedAdmin',
519
+            'ldap_dynamic_group_member_url'     => 'ldapDynamicGroupMemberURL',
520
+        );
521
+        return $array;
522
+    }
523 523
 
524 524
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Group_LDAP.php 2 patches
Indentation   +1037 added lines, -1037 removed lines patch added patch discarded remove patch
@@ -41,1041 +41,1041 @@
 block discarded – undo
41 41
 use OC\Cache\CappedMemoryCache;
42 42
 
43 43
 class Group_LDAP extends BackendUtility implements \OCP\GroupInterface {
44
-	protected $enabled = false;
45
-
46
-	/**
47
-	 * @var string[] $cachedGroupMembers array of users with gid as key
48
-	 */
49
-	protected $cachedGroupMembers;
50
-
51
-	/**
52
-	 * @var string[] $cachedGroupsByMember array of groups with uid as key
53
-	 */
54
-	protected $cachedGroupsByMember;
55
-
56
-	public function __construct(Access $access) {
57
-		parent::__construct($access);
58
-		$filter = $this->access->connection->ldapGroupFilter;
59
-		$gassoc = $this->access->connection->ldapGroupMemberAssocAttr;
60
-		if(!empty($filter) && !empty($gassoc)) {
61
-			$this->enabled = true;
62
-		}
63
-
64
-		$this->cachedGroupMembers = new CappedMemoryCache();
65
-		$this->cachedGroupsByMember = new CappedMemoryCache();
66
-	}
67
-
68
-	/**
69
-	 * is user in group?
70
-	 * @param string $uid uid of the user
71
-	 * @param string $gid gid of the group
72
-	 * @return bool
73
-	 *
74
-	 * Checks whether the user is member of a group or not.
75
-	 */
76
-	public function inGroup($uid, $gid) {
77
-		if(!$this->enabled) {
78
-			return false;
79
-		}
80
-		$cacheKey = 'inGroup'.$uid.':'.$gid;
81
-		$inGroup = $this->access->connection->getFromCache($cacheKey);
82
-		if(!is_null($inGroup)) {
83
-			return (bool)$inGroup;
84
-		}
85
-
86
-		$userDN = $this->access->username2dn($uid);
87
-
88
-		if(isset($this->cachedGroupMembers[$gid])) {
89
-			$isInGroup = in_array($userDN, $this->cachedGroupMembers[$gid]);
90
-			return $isInGroup;
91
-		}
92
-
93
-		$cacheKeyMembers = 'inGroup-members:'.$gid;
94
-		$members = $this->access->connection->getFromCache($cacheKeyMembers);
95
-		if(!is_null($members)) {
96
-			$this->cachedGroupMembers[$gid] = $members;
97
-			$isInGroup = in_array($userDN, $members);
98
-			$this->access->connection->writeToCache($cacheKey, $isInGroup);
99
-			return $isInGroup;
100
-		}
101
-
102
-		$groupDN = $this->access->groupname2dn($gid);
103
-		// just in case
104
-		if(!$groupDN || !$userDN) {
105
-			$this->access->connection->writeToCache($cacheKey, false);
106
-			return false;
107
-		}
108
-
109
-		//check primary group first
110
-		if($gid === $this->getUserPrimaryGroup($userDN)) {
111
-			$this->access->connection->writeToCache($cacheKey, true);
112
-			return true;
113
-		}
114
-
115
-		//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
116
-		$members = $this->_groupMembers($groupDN);
117
-		$members = array_keys($members); // uids are returned as keys
118
-		if(!is_array($members) || count($members) === 0) {
119
-			$this->access->connection->writeToCache($cacheKey, false);
120
-			return false;
121
-		}
122
-
123
-		//extra work if we don't get back user DNs
124
-		if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
125
-			$dns = array();
126
-			$filterParts = array();
127
-			$bytes = 0;
128
-			foreach($members as $mid) {
129
-				$filter = str_replace('%uid', $mid, $this->access->connection->ldapLoginFilter);
130
-				$filterParts[] = $filter;
131
-				$bytes += strlen($filter);
132
-				if($bytes >= 9000000) {
133
-					// AD has a default input buffer of 10 MB, we do not want
134
-					// to take even the chance to exceed it
135
-					$filter = $this->access->combineFilterWithOr($filterParts);
136
-					$bytes = 0;
137
-					$filterParts = array();
138
-					$users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
139
-					$dns = array_merge($dns, $users);
140
-				}
141
-			}
142
-			if(count($filterParts) > 0) {
143
-				$filter = $this->access->combineFilterWithOr($filterParts);
144
-				$users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
145
-				$dns = array_merge($dns, $users);
146
-			}
147
-			$members = $dns;
148
-		}
149
-
150
-		$isInGroup = in_array($userDN, $members);
151
-		$this->access->connection->writeToCache($cacheKey, $isInGroup);
152
-		$this->access->connection->writeToCache($cacheKeyMembers, $members);
153
-		$this->cachedGroupMembers[$gid] = $members;
154
-
155
-		return $isInGroup;
156
-	}
157
-
158
-	/**
159
-	 * @param string $dnGroup
160
-	 * @return array
161
-	 *
162
-	 * For a group that has user membership defined by an LDAP search url attribute returns the users
163
-	 * that match the search url otherwise returns an empty array.
164
-	 */
165
-	public function getDynamicGroupMembers($dnGroup) {
166
-		$dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
167
-
168
-		if (empty($dynamicGroupMemberURL)) {
169
-			return array();
170
-		}
171
-
172
-		$dynamicMembers = array();
173
-		$memberURLs = $this->access->readAttribute(
174
-			$dnGroup,
175
-			$dynamicGroupMemberURL,
176
-			$this->access->connection->ldapGroupFilter
177
-		);
178
-		if ($memberURLs !== false) {
179
-			// this group has the 'memberURL' attribute so this is a dynamic group
180
-			// example 1: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(o=HeadOffice)
181
-			// example 2: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(&(o=HeadOffice)(uidNumber>=500))
182
-			$pos = strpos($memberURLs[0], '(');
183
-			if ($pos !== false) {
184
-				$memberUrlFilter = substr($memberURLs[0], $pos);
185
-				$foundMembers = $this->access->searchUsers($memberUrlFilter,'dn');
186
-				$dynamicMembers = array();
187
-				foreach($foundMembers as $value) {
188
-					$dynamicMembers[$value['dn'][0]] = 1;
189
-				}
190
-			} else {
191
-				\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
192
-					'of group ' . $dnGroup, \OCP\Util::DEBUG);
193
-			}
194
-		}
195
-		return $dynamicMembers;
196
-	}
197
-
198
-	/**
199
-	 * @param string $dnGroup
200
-	 * @param array|null &$seen
201
-	 * @return array|mixed|null
202
-	 */
203
-	private function _groupMembers($dnGroup, &$seen = null) {
204
-		if ($seen === null) {
205
-			$seen = array();
206
-		}
207
-		$allMembers = array();
208
-		if (array_key_exists($dnGroup, $seen)) {
209
-			// avoid loops
210
-			return array();
211
-		}
212
-		// used extensively in cron job, caching makes sense for nested groups
213
-		$cacheKey = '_groupMembers'.$dnGroup;
214
-		$groupMembers = $this->access->connection->getFromCache($cacheKey);
215
-		if(!is_null($groupMembers)) {
216
-			return $groupMembers;
217
-		}
218
-		$seen[$dnGroup] = 1;
219
-		$members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr,
220
-												$this->access->connection->ldapGroupFilter);
221
-		if (is_array($members)) {
222
-			foreach ($members as $memberDN) {
223
-				$allMembers[$memberDN] = 1;
224
-				$nestedGroups = $this->access->connection->ldapNestedGroups;
225
-				if (!empty($nestedGroups)) {
226
-					$subMembers = $this->_groupMembers($memberDN, $seen);
227
-					if ($subMembers) {
228
-						$allMembers = array_merge($allMembers, $subMembers);
229
-					}
230
-				}
231
-			}
232
-		}
233
-
234
-		$allMembers = array_merge($allMembers, $this->getDynamicGroupMembers($dnGroup));
235
-
236
-		$this->access->connection->writeToCache($cacheKey, $allMembers);
237
-		return $allMembers;
238
-	}
239
-
240
-	/**
241
-	 * @param string $DN
242
-	 * @param array|null &$seen
243
-	 * @return array
244
-	 */
245
-	private function _getGroupDNsFromMemberOf($DN, &$seen = null) {
246
-		if ($seen === null) {
247
-			$seen = array();
248
-		}
249
-		if (array_key_exists($DN, $seen)) {
250
-			// avoid loops
251
-			return array();
252
-		}
253
-		$seen[$DN] = 1;
254
-		$groups = $this->access->readAttribute($DN, 'memberOf');
255
-		if (!is_array($groups)) {
256
-			return array();
257
-		}
258
-		$groups = $this->access->groupsMatchFilter($groups);
259
-		$allGroups =  $groups;
260
-		$nestedGroups = $this->access->connection->ldapNestedGroups;
261
-		if (intval($nestedGroups) === 1) {
262
-			foreach ($groups as $group) {
263
-				$subGroups = $this->_getGroupDNsFromMemberOf($group, $seen);
264
-				$allGroups = array_merge($allGroups, $subGroups);
265
-			}
266
-		}
267
-		return $allGroups;
268
-	}
269
-
270
-	/**
271
-	 * translates a gidNumber into an ownCloud internal name
272
-	 * @param string $gid as given by gidNumber on POSIX LDAP
273
-	 * @param string $dn a DN that belongs to the same domain as the group
274
-	 * @return string|bool
275
-	 */
276
-	public function gidNumber2Name($gid, $dn) {
277
-		$cacheKey = 'gidNumberToName';
278
-		$groupNames = $this->access->connection->getFromCache($cacheKey);
279
-		if(!is_null($groupNames) && isset($groupNames[$gid])) {
280
-			return $groupNames[$gid];
281
-		}
282
-
283
-		//we need to get the DN from LDAP
284
-		$filter = $this->access->combineFilterWithAnd([
285
-			$this->access->connection->ldapGroupFilter,
286
-			'objectClass=posixGroup',
287
-			$this->access->connection->ldapGidNumber . '=' . $gid
288
-		]);
289
-		$result = $this->access->searchGroups($filter, array('dn'), 1);
290
-		if(empty($result)) {
291
-			return false;
292
-		}
293
-		$dn = $result[0]['dn'][0];
294
-
295
-		//and now the group name
296
-		//NOTE once we have separate ownCloud group IDs and group names we can
297
-		//directly read the display name attribute instead of the DN
298
-		$name = $this->access->dn2groupname($dn);
299
-
300
-		$this->access->connection->writeToCache($cacheKey, $name);
301
-
302
-		return $name;
303
-	}
304
-
305
-	/**
306
-	 * returns the entry's gidNumber
307
-	 * @param string $dn
308
-	 * @param string $attribute
309
-	 * @return string|bool
310
-	 */
311
-	private function getEntryGidNumber($dn, $attribute) {
312
-		$value = $this->access->readAttribute($dn, $attribute);
313
-		if(is_array($value) && !empty($value)) {
314
-			return $value[0];
315
-		}
316
-		return false;
317
-	}
318
-
319
-	/**
320
-	 * returns the group's primary ID
321
-	 * @param string $dn
322
-	 * @return string|bool
323
-	 */
324
-	public function getGroupGidNumber($dn) {
325
-		return $this->getEntryGidNumber($dn, 'gidNumber');
326
-	}
327
-
328
-	/**
329
-	 * returns the user's gidNumber
330
-	 * @param string $dn
331
-	 * @return string|bool
332
-	 */
333
-	public function getUserGidNumber($dn) {
334
-		$gidNumber = false;
335
-		if($this->access->connection->hasGidNumber) {
336
-			$gidNumber = $this->getEntryGidNumber($dn, 'gidNumber');
337
-			if($gidNumber === false) {
338
-				$this->access->connection->hasGidNumber = false;
339
-			}
340
-		}
341
-		return $gidNumber;
342
-	}
343
-
344
-	/**
345
-	 * returns a filter for a "users has specific gid" search or count operation
346
-	 *
347
-	 * @param string $groupDN
348
-	 * @param string $search
349
-	 * @return string
350
-	 * @throws \Exception
351
-	 */
352
-	private function prepareFilterForUsersHasGidNumber($groupDN, $search = '') {
353
-		$groupID = $this->getGroupGidNumber($groupDN);
354
-		if($groupID === false) {
355
-			throw new \Exception('Not a valid group');
356
-		}
357
-
358
-		$filterParts = [];
359
-		$filterParts[] = $this->access->getFilterForUserCount();
360
-		if ($search !== '') {
361
-			$filterParts[] = $this->access->getFilterPartForUserSearch($search);
362
-		}
363
-		$filterParts[] = $this->access->connection->ldapGidNumber .'=' . $groupID;
364
-
365
-		$filter = $this->access->combineFilterWithAnd($filterParts);
366
-
367
-		return $filter;
368
-	}
369
-
370
-	/**
371
-	 * returns a list of users that have the given group as gid number
372
-	 *
373
-	 * @param string $groupDN
374
-	 * @param string $search
375
-	 * @param int $limit
376
-	 * @param int $offset
377
-	 * @return string[]
378
-	 */
379
-	public function getUsersInGidNumber($groupDN, $search = '', $limit = -1, $offset = 0) {
380
-		try {
381
-			$filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search);
382
-			$users = $this->access->fetchListOfUsers(
383
-				$filter,
384
-				[$this->access->connection->ldapUserDisplayName, 'dn'],
385
-				$limit,
386
-				$offset
387
-			);
388
-			return $this->access->ownCloudUserNames($users);
389
-		} catch (\Exception $e) {
390
-			return [];
391
-		}
392
-	}
393
-
394
-	/**
395
-	 * returns the number of users that have the given group as gid number
396
-	 *
397
-	 * @param string $groupDN
398
-	 * @param string $search
399
-	 * @param int $limit
400
-	 * @param int $offset
401
-	 * @return int
402
-	 */
403
-	public function countUsersInGidNumber($groupDN, $search = '', $limit = -1, $offset = 0) {
404
-		try {
405
-			$filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search);
406
-			$users = $this->access->countUsers($filter, ['dn'], $limit, $offset);
407
-			return (int)$users;
408
-		} catch (\Exception $e) {
409
-			return 0;
410
-		}
411
-	}
412
-
413
-	/**
414
-	 * gets the gidNumber of a user
415
-	 * @param string $dn
416
-	 * @return string
417
-	 */
418
-	public function getUserGroupByGid($dn) {
419
-		$groupID = $this->getUserGidNumber($dn);
420
-		if($groupID !== false) {
421
-			$groupName = $this->gidNumber2Name($groupID, $dn);
422
-			if($groupName !== false) {
423
-				return $groupName;
424
-			}
425
-		}
426
-
427
-		return false;
428
-	}
429
-
430
-	/**
431
-	 * translates a primary group ID into an ownCloud internal name
432
-	 * @param string $gid as given by primaryGroupID on AD
433
-	 * @param string $dn a DN that belongs to the same domain as the group
434
-	 * @return string|bool
435
-	 */
436
-	public function primaryGroupID2Name($gid, $dn) {
437
-		$cacheKey = 'primaryGroupIDtoName';
438
-		$groupNames = $this->access->connection->getFromCache($cacheKey);
439
-		if(!is_null($groupNames) && isset($groupNames[$gid])) {
440
-			return $groupNames[$gid];
441
-		}
442
-
443
-		$domainObjectSid = $this->access->getSID($dn);
444
-		if($domainObjectSid === false) {
445
-			return false;
446
-		}
447
-
448
-		//we need to get the DN from LDAP
449
-		$filter = $this->access->combineFilterWithAnd(array(
450
-			$this->access->connection->ldapGroupFilter,
451
-			'objectsid=' . $domainObjectSid . '-' . $gid
452
-		));
453
-		$result = $this->access->searchGroups($filter, array('dn'), 1);
454
-		if(empty($result)) {
455
-			return false;
456
-		}
457
-		$dn = $result[0]['dn'][0];
458
-
459
-		//and now the group name
460
-		//NOTE once we have separate ownCloud group IDs and group names we can
461
-		//directly read the display name attribute instead of the DN
462
-		$name = $this->access->dn2groupname($dn);
463
-
464
-		$this->access->connection->writeToCache($cacheKey, $name);
465
-
466
-		return $name;
467
-	}
468
-
469
-	/**
470
-	 * returns the entry's primary group ID
471
-	 * @param string $dn
472
-	 * @param string $attribute
473
-	 * @return string|bool
474
-	 */
475
-	private function getEntryGroupID($dn, $attribute) {
476
-		$value = $this->access->readAttribute($dn, $attribute);
477
-		if(is_array($value) && !empty($value)) {
478
-			return $value[0];
479
-		}
480
-		return false;
481
-	}
482
-
483
-	/**
484
-	 * returns the group's primary ID
485
-	 * @param string $dn
486
-	 * @return string|bool
487
-	 */
488
-	public function getGroupPrimaryGroupID($dn) {
489
-		return $this->getEntryGroupID($dn, 'primaryGroupToken');
490
-	}
491
-
492
-	/**
493
-	 * returns the user's primary group ID
494
-	 * @param string $dn
495
-	 * @return string|bool
496
-	 */
497
-	public function getUserPrimaryGroupIDs($dn) {
498
-		$primaryGroupID = false;
499
-		if($this->access->connection->hasPrimaryGroups) {
500
-			$primaryGroupID = $this->getEntryGroupID($dn, 'primaryGroupID');
501
-			if($primaryGroupID === false) {
502
-				$this->access->connection->hasPrimaryGroups = false;
503
-			}
504
-		}
505
-		return $primaryGroupID;
506
-	}
507
-
508
-	/**
509
-	 * returns a filter for a "users in primary group" search or count operation
510
-	 *
511
-	 * @param string $groupDN
512
-	 * @param string $search
513
-	 * @return string
514
-	 * @throws \Exception
515
-	 */
516
-	private function prepareFilterForUsersInPrimaryGroup($groupDN, $search = '') {
517
-		$groupID = $this->getGroupPrimaryGroupID($groupDN);
518
-		if($groupID === false) {
519
-			throw new \Exception('Not a valid group');
520
-		}
521
-
522
-		$filterParts = [];
523
-		$filterParts[] = $this->access->getFilterForUserCount();
524
-		if ($search !== '') {
525
-			$filterParts[] = $this->access->getFilterPartForUserSearch($search);
526
-		}
527
-		$filterParts[] = 'primaryGroupID=' . $groupID;
528
-
529
-		$filter = $this->access->combineFilterWithAnd($filterParts);
530
-
531
-		return $filter;
532
-	}
533
-
534
-	/**
535
-	 * returns a list of users that have the given group as primary group
536
-	 *
537
-	 * @param string $groupDN
538
-	 * @param string $search
539
-	 * @param int $limit
540
-	 * @param int $offset
541
-	 * @return string[]
542
-	 */
543
-	public function getUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
544
-		try {
545
-			$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
546
-			$users = $this->access->fetchListOfUsers(
547
-				$filter,
548
-				array($this->access->connection->ldapUserDisplayName, 'dn'),
549
-				$limit,
550
-				$offset
551
-			);
552
-			return $this->access->ownCloudUserNames($users);
553
-		} catch (\Exception $e) {
554
-			return array();
555
-		}
556
-	}
557
-
558
-	/**
559
-	 * returns the number of users that have the given group as primary group
560
-	 *
561
-	 * @param string $groupDN
562
-	 * @param string $search
563
-	 * @param int $limit
564
-	 * @param int $offset
565
-	 * @return int
566
-	 */
567
-	public function countUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
568
-		try {
569
-			$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
570
-			$users = $this->access->countUsers($filter, array('dn'), $limit, $offset);
571
-			return (int)$users;
572
-		} catch (\Exception $e) {
573
-			return 0;
574
-		}
575
-	}
576
-
577
-	/**
578
-	 * gets the primary group of a user
579
-	 * @param string $dn
580
-	 * @return string
581
-	 */
582
-	public function getUserPrimaryGroup($dn) {
583
-		$groupID = $this->getUserPrimaryGroupIDs($dn);
584
-		if($groupID !== false) {
585
-			$groupName = $this->primaryGroupID2Name($groupID, $dn);
586
-			if($groupName !== false) {
587
-				return $groupName;
588
-			}
589
-		}
590
-
591
-		return false;
592
-	}
593
-
594
-	/**
595
-	 * Get all groups a user belongs to
596
-	 * @param string $uid Name of the user
597
-	 * @return array with group names
598
-	 *
599
-	 * This function fetches all groups a user belongs to. It does not check
600
-	 * if the user exists at all.
601
-	 *
602
-	 * This function includes groups based on dynamic group membership.
603
-	 */
604
-	public function getUserGroups($uid) {
605
-		if(!$this->enabled) {
606
-			return array();
607
-		}
608
-		$cacheKey = 'getUserGroups'.$uid;
609
-		$userGroups = $this->access->connection->getFromCache($cacheKey);
610
-		if(!is_null($userGroups)) {
611
-			return $userGroups;
612
-		}
613
-		$userDN = $this->access->username2dn($uid);
614
-		if(!$userDN) {
615
-			$this->access->connection->writeToCache($cacheKey, array());
616
-			return array();
617
-		}
618
-
619
-		$groups = [];
620
-		$primaryGroup = $this->getUserPrimaryGroup($userDN);
621
-		$gidGroupName = $this->getUserGroupByGid($userDN);
622
-
623
-		$dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
624
-
625
-		if (!empty($dynamicGroupMemberURL)) {
626
-			// look through dynamic groups to add them to the result array if needed
627
-			$groupsToMatch = $this->access->fetchListOfGroups(
628
-				$this->access->connection->ldapGroupFilter,array('dn',$dynamicGroupMemberURL));
629
-			foreach($groupsToMatch as $dynamicGroup) {
630
-				if (!array_key_exists($dynamicGroupMemberURL, $dynamicGroup)) {
631
-					continue;
632
-				}
633
-				$pos = strpos($dynamicGroup[$dynamicGroupMemberURL][0], '(');
634
-				if ($pos !== false) {
635
-					$memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0],$pos);
636
-					// apply filter via ldap search to see if this user is in this
637
-					// dynamic group
638
-					$userMatch = $this->access->readAttribute(
639
-						$userDN,
640
-						$this->access->connection->ldapUserDisplayName,
641
-						$memberUrlFilter
642
-					);
643
-					if ($userMatch !== false) {
644
-						// match found so this user is in this group
645
-						$groupName = $this->access->dn2groupname($dynamicGroup['dn'][0]);
646
-						if(is_string($groupName)) {
647
-							// be sure to never return false if the dn could not be
648
-							// resolved to a name, for whatever reason.
649
-							$groups[] = $groupName;
650
-						}
651
-					}
652
-				} else {
653
-					\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
654
-						'of group ' . print_r($dynamicGroup, true), \OCP\Util::DEBUG);
655
-				}
656
-			}
657
-		}
658
-
659
-		// if possible, read out membership via memberOf. It's far faster than
660
-		// performing a search, which still is a fallback later.
661
-		if(intval($this->access->connection->hasMemberOfFilterSupport) === 1
662
-			&& intval($this->access->connection->useMemberOfToDetectMembership) === 1
663
-		) {
664
-			$groupDNs = $this->_getGroupDNsFromMemberOf($userDN);
665
-			if (is_array($groupDNs)) {
666
-				foreach ($groupDNs as $dn) {
667
-					$groupName = $this->access->dn2groupname($dn);
668
-					if(is_string($groupName)) {
669
-						// be sure to never return false if the dn could not be
670
-						// resolved to a name, for whatever reason.
671
-						$groups[] = $groupName;
672
-					}
673
-				}
674
-			}
675
-
676
-			if($primaryGroup !== false) {
677
-				$groups[] = $primaryGroup;
678
-			}
679
-			if($gidGroupName !== false) {
680
-				$groups[] = $gidGroupName;
681
-			}
682
-			$this->access->connection->writeToCache($cacheKey, $groups);
683
-			return $groups;
684
-		}
685
-
686
-		//uniqueMember takes DN, memberuid the uid, so we need to distinguish
687
-		if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
688
-			|| (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member')
689
-		) {
690
-			$uid = $userDN;
691
-		} else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
692
-			$result = $this->access->readAttribute($userDN, 'uid');
693
-			if ($result === false) {
694
-				\OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '.
695
-					$this->access->connection->ldapHost, \OCP\Util::DEBUG);
696
-			}
697
-			$uid = $result[0];
698
-		} else {
699
-			// just in case
700
-			$uid = $userDN;
701
-		}
702
-
703
-		if(isset($this->cachedGroupsByMember[$uid])) {
704
-			$groups = array_merge($groups, $this->cachedGroupsByMember[$uid]);
705
-		} else {
706
-			$groupsByMember = array_values($this->getGroupsByMember($uid));
707
-			$groupsByMember = $this->access->ownCloudGroupNames($groupsByMember);
708
-			$this->cachedGroupsByMember[$uid] = $groupsByMember;
709
-			$groups = array_merge($groups, $groupsByMember);
710
-		}
711
-
712
-		if($primaryGroup !== false) {
713
-			$groups[] = $primaryGroup;
714
-		}
715
-		if($gidGroupName !== false) {
716
-			$groups[] = $gidGroupName;
717
-		}
718
-
719
-		$groups = array_unique($groups, SORT_LOCALE_STRING);
720
-		$this->access->connection->writeToCache($cacheKey, $groups);
721
-
722
-		return $groups;
723
-	}
724
-
725
-	/**
726
-	 * @param string $dn
727
-	 * @param array|null &$seen
728
-	 * @return array
729
-	 */
730
-	private function getGroupsByMember($dn, &$seen = null) {
731
-		if ($seen === null) {
732
-			$seen = array();
733
-		}
734
-		$allGroups = array();
735
-		if (array_key_exists($dn, $seen)) {
736
-			// avoid loops
737
-			return array();
738
-		}
739
-		$seen[$dn] = true;
740
-		$filter = $this->access->combineFilterWithAnd(array(
741
-			$this->access->connection->ldapGroupFilter,
742
-			$this->access->connection->ldapGroupMemberAssocAttr.'='.$dn
743
-		));
744
-		$groups = $this->access->fetchListOfGroups($filter,
745
-			array($this->access->connection->ldapGroupDisplayName, 'dn'));
746
-		if (is_array($groups)) {
747
-			foreach ($groups as $groupobj) {
748
-				$groupDN = $groupobj['dn'][0];
749
-				$allGroups[$groupDN] = $groupobj;
750
-				$nestedGroups = $this->access->connection->ldapNestedGroups;
751
-				if (!empty($nestedGroups)) {
752
-					$supergroups = $this->getGroupsByMember($groupDN, $seen);
753
-					if (is_array($supergroups) && (count($supergroups)>0)) {
754
-						$allGroups = array_merge($allGroups, $supergroups);
755
-					}
756
-				}
757
-			}
758
-		}
759
-		return $allGroups;
760
-	}
761
-
762
-	/**
763
-	 * get a list of all users in a group
764
-	 *
765
-	 * @param string $gid
766
-	 * @param string $search
767
-	 * @param int $limit
768
-	 * @param int $offset
769
-	 * @return array with user ids
770
-	 */
771
-	public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
772
-		if(!$this->enabled) {
773
-			return array();
774
-		}
775
-		if(!$this->groupExists($gid)) {
776
-			return array();
777
-		}
778
-		$search = $this->access->escapeFilterPart($search, true);
779
-		$cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
780
-		// check for cache of the exact query
781
-		$groupUsers = $this->access->connection->getFromCache($cacheKey);
782
-		if(!is_null($groupUsers)) {
783
-			return $groupUsers;
784
-		}
785
-
786
-		// check for cache of the query without limit and offset
787
-		$groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
788
-		if(!is_null($groupUsers)) {
789
-			$groupUsers = array_slice($groupUsers, $offset, $limit);
790
-			$this->access->connection->writeToCache($cacheKey, $groupUsers);
791
-			return $groupUsers;
792
-		}
793
-
794
-		if($limit === -1) {
795
-			$limit = null;
796
-		}
797
-		$groupDN = $this->access->groupname2dn($gid);
798
-		if(!$groupDN) {
799
-			// group couldn't be found, return empty resultset
800
-			$this->access->connection->writeToCache($cacheKey, array());
801
-			return array();
802
-		}
803
-
804
-		$primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset);
805
-		$members = array_keys($this->_groupMembers($groupDN));
806
-		if(!$members && empty($primaryUsers)) {
807
-			//in case users could not be retrieved, return empty result set
808
-			$this->access->connection->writeToCache($cacheKey, array());
809
-			return array();
810
-		}
811
-
812
-		$groupUsers = array();
813
-		$isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid');
814
-		$attrs = $this->access->userManager->getAttributes(true);
815
-		foreach($members as $member) {
816
-			if($isMemberUid) {
817
-				//we got uids, need to get their DNs to 'translate' them to user names
818
-				$filter = $this->access->combineFilterWithAnd(array(
819
-					str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
820
-					$this->access->getFilterPartForUserSearch($search)
821
-				));
822
-				$ldap_users = $this->access->fetchListOfUsers($filter, $attrs, 1);
823
-				if(count($ldap_users) < 1) {
824
-					continue;
825
-				}
826
-				$groupUsers[] = $this->access->dn2username($ldap_users[0]['dn'][0]);
827
-			} else {
828
-				//we got DNs, check if we need to filter by search or we can give back all of them
829
-				if ($search !== '') {
830
-					if(!$this->access->readAttribute($member,
831
-						$this->access->connection->ldapUserDisplayName,
832
-						$this->access->getFilterPartForUserSearch($search))) {
833
-						continue;
834
-					}
835
-				}
836
-				// dn2username will also check if the users belong to the allowed base
837
-				if($ocname = $this->access->dn2username($member)) {
838
-					$groupUsers[] = $ocname;
839
-				}
840
-			}
841
-		}
842
-
843
-		$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
844
-		natsort($groupUsers);
845
-		$this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
846
-		$groupUsers = array_slice($groupUsers, $offset, $limit);
847
-
848
-
849
-		$this->access->connection->writeToCache($cacheKey, $groupUsers);
850
-
851
-		return $groupUsers;
852
-	}
853
-
854
-	/**
855
-	 * returns the number of users in a group, who match the search term
856
-	 * @param string $gid the internal group name
857
-	 * @param string $search optional, a search string
858
-	 * @return int|bool
859
-	 */
860
-	public function countUsersInGroup($gid, $search = '') {
861
-		$cacheKey = 'countUsersInGroup-'.$gid.'-'.$search;
862
-		if(!$this->enabled || !$this->groupExists($gid)) {
863
-			return false;
864
-		}
865
-		$groupUsers = $this->access->connection->getFromCache($cacheKey);
866
-		if(!is_null($groupUsers)) {
867
-			return $groupUsers;
868
-		}
869
-
870
-		$groupDN = $this->access->groupname2dn($gid);
871
-		if(!$groupDN) {
872
-			// group couldn't be found, return empty result set
873
-			$this->access->connection->writeToCache($cacheKey, false);
874
-			return false;
875
-		}
876
-
877
-		$members = array_keys($this->_groupMembers($groupDN));
878
-		$primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, '');
879
-		if(!$members && $primaryUserCount === 0) {
880
-			//in case users could not be retrieved, return empty result set
881
-			$this->access->connection->writeToCache($cacheKey, false);
882
-			return false;
883
-		}
884
-
885
-		if ($search === '') {
886
-			$groupUsers = count($members) + $primaryUserCount;
887
-			$this->access->connection->writeToCache($cacheKey, $groupUsers);
888
-			return $groupUsers;
889
-		}
890
-		$search = $this->access->escapeFilterPart($search, true);
891
-		$isMemberUid =
892
-			(strtolower($this->access->connection->ldapGroupMemberAssocAttr)
893
-			=== 'memberuid');
894
-
895
-		//we need to apply the search filter
896
-		//alternatives that need to be checked:
897
-		//a) get all users by search filter and array_intersect them
898
-		//b) a, but only when less than 1k 10k ?k users like it is
899
-		//c) put all DNs|uids in a LDAP filter, combine with the search string
900
-		//   and let it count.
901
-		//For now this is not important, because the only use of this method
902
-		//does not supply a search string
903
-		$groupUsers = array();
904
-		foreach($members as $member) {
905
-			if($isMemberUid) {
906
-				//we got uids, need to get their DNs to 'translate' them to user names
907
-				$filter = $this->access->combineFilterWithAnd(array(
908
-					str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
909
-					$this->access->getFilterPartForUserSearch($search)
910
-				));
911
-				$ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1);
912
-				if(count($ldap_users) < 1) {
913
-					continue;
914
-				}
915
-				$groupUsers[] = $this->access->dn2username($ldap_users[0]);
916
-			} else {
917
-				//we need to apply the search filter now
918
-				if(!$this->access->readAttribute($member,
919
-					$this->access->connection->ldapUserDisplayName,
920
-					$this->access->getFilterPartForUserSearch($search))) {
921
-					continue;
922
-				}
923
-				// dn2username will also check if the users belong to the allowed base
924
-				if($ocname = $this->access->dn2username($member)) {
925
-					$groupUsers[] = $ocname;
926
-				}
927
-			}
928
-		}
929
-
930
-		//and get users that have the group as primary
931
-		$primaryUsers = $this->countUsersInPrimaryGroup($groupDN, $search);
932
-
933
-		return count($groupUsers) + $primaryUsers;
934
-	}
935
-
936
-	/**
937
-	 * get a list of all groups
938
-	 *
939
-	 * @param string $search
940
-	 * @param $limit
941
-	 * @param int $offset
942
-	 * @return array with group names
943
-	 *
944
-	 * Returns a list with all groups (used by getGroups)
945
-	 */
946
-	protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) {
947
-		if(!$this->enabled) {
948
-			return array();
949
-		}
950
-		$cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset;
951
-
952
-		//Check cache before driving unnecessary searches
953
-		\OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG);
954
-		$ldap_groups = $this->access->connection->getFromCache($cacheKey);
955
-		if(!is_null($ldap_groups)) {
956
-			return $ldap_groups;
957
-		}
958
-
959
-		// if we'd pass -1 to LDAP search, we'd end up in a Protocol
960
-		// error. With a limit of 0, we get 0 results. So we pass null.
961
-		if($limit <= 0) {
962
-			$limit = null;
963
-		}
964
-		$filter = $this->access->combineFilterWithAnd(array(
965
-			$this->access->connection->ldapGroupFilter,
966
-			$this->access->getFilterPartForGroupSearch($search)
967
-		));
968
-		\OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, \OCP\Util::DEBUG);
969
-		$ldap_groups = $this->access->fetchListOfGroups($filter,
970
-				array($this->access->connection->ldapGroupDisplayName, 'dn'),
971
-				$limit,
972
-				$offset);
973
-		$ldap_groups = $this->access->ownCloudGroupNames($ldap_groups);
974
-
975
-		$this->access->connection->writeToCache($cacheKey, $ldap_groups);
976
-		return $ldap_groups;
977
-	}
978
-
979
-	/**
980
-	 * get a list of all groups using a paged search
981
-	 *
982
-	 * @param string $search
983
-	 * @param int $limit
984
-	 * @param int $offset
985
-	 * @return array with group names
986
-	 *
987
-	 * Returns a list with all groups
988
-	 * Uses a paged search if available to override a
989
-	 * server side search limit.
990
-	 * (active directory has a limit of 1000 by default)
991
-	 */
992
-	public function getGroups($search = '', $limit = -1, $offset = 0) {
993
-		if(!$this->enabled) {
994
-			return array();
995
-		}
996
-		$search = $this->access->escapeFilterPart($search, true);
997
-		$pagingSize = intval($this->access->connection->ldapPagingSize);
998
-		if (!$this->access->connection->hasPagedResultSupport || $pagingSize <= 0) {
999
-			return $this->getGroupsChunk($search, $limit, $offset);
1000
-		}
1001
-		$maxGroups = 100000; // limit max results (just for safety reasons)
1002
-		if ($limit > -1) {
1003
-		   $overallLimit = min($limit + $offset, $maxGroups);
1004
-		} else {
1005
-		   $overallLimit = $maxGroups;
1006
-		}
1007
-		$chunkOffset = $offset;
1008
-		$allGroups = array();
1009
-		while ($chunkOffset < $overallLimit) {
1010
-			$chunkLimit = min($pagingSize, $overallLimit - $chunkOffset);
1011
-			$ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset);
1012
-			$nread = count($ldapGroups);
1013
-			\OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', \OCP\Util::DEBUG);
1014
-			if ($nread) {
1015
-				$allGroups = array_merge($allGroups, $ldapGroups);
1016
-				$chunkOffset += $nread;
1017
-			}
1018
-			if ($nread < $chunkLimit) {
1019
-				break;
1020
-			}
1021
-		}
1022
-		return $allGroups;
1023
-	}
1024
-
1025
-	/**
1026
-	 * @param string $group
1027
-	 * @return bool
1028
-	 */
1029
-	public function groupMatchesFilter($group) {
1030
-		return (strripos($group, $this->groupSearch) !== false);
1031
-	}
1032
-
1033
-	/**
1034
-	 * check if a group exists
1035
-	 * @param string $gid
1036
-	 * @return bool
1037
-	 */
1038
-	public function groupExists($gid) {
1039
-		$groupExists = $this->access->connection->getFromCache('groupExists'.$gid);
1040
-		if(!is_null($groupExists)) {
1041
-			return (bool)$groupExists;
1042
-		}
1043
-
1044
-		//getting dn, if false the group does not exist. If dn, it may be mapped
1045
-		//only, requires more checking.
1046
-		$dn = $this->access->groupname2dn($gid);
1047
-		if(!$dn) {
1048
-			$this->access->connection->writeToCache('groupExists'.$gid, false);
1049
-			return false;
1050
-		}
1051
-
1052
-		//if group really still exists, we will be able to read its objectclass
1053
-		if(!is_array($this->access->readAttribute($dn, ''))) {
1054
-			$this->access->connection->writeToCache('groupExists'.$gid, false);
1055
-			return false;
1056
-		}
1057
-
1058
-		$this->access->connection->writeToCache('groupExists'.$gid, true);
1059
-		return true;
1060
-	}
1061
-
1062
-	/**
1063
-	* Check if backend implements actions
1064
-	* @param int $actions bitwise-or'ed actions
1065
-	* @return boolean
1066
-	*
1067
-	* Returns the supported actions as int to be
1068
-	* compared with OC_USER_BACKEND_CREATE_USER etc.
1069
-	*/
1070
-	public function implementsActions($actions) {
1071
-		return (bool)(\OC\Group\Backend::COUNT_USERS & $actions);
1072
-	}
1073
-
1074
-	/**
1075
-	 * Return access for LDAP interaction.
1076
-	 * @return Access instance of Access for LDAP interaction
1077
-	 */
1078
-	public function getLDAPAccess() {
1079
-		return $this->access;
1080
-	}
44
+    protected $enabled = false;
45
+
46
+    /**
47
+     * @var string[] $cachedGroupMembers array of users with gid as key
48
+     */
49
+    protected $cachedGroupMembers;
50
+
51
+    /**
52
+     * @var string[] $cachedGroupsByMember array of groups with uid as key
53
+     */
54
+    protected $cachedGroupsByMember;
55
+
56
+    public function __construct(Access $access) {
57
+        parent::__construct($access);
58
+        $filter = $this->access->connection->ldapGroupFilter;
59
+        $gassoc = $this->access->connection->ldapGroupMemberAssocAttr;
60
+        if(!empty($filter) && !empty($gassoc)) {
61
+            $this->enabled = true;
62
+        }
63
+
64
+        $this->cachedGroupMembers = new CappedMemoryCache();
65
+        $this->cachedGroupsByMember = new CappedMemoryCache();
66
+    }
67
+
68
+    /**
69
+     * is user in group?
70
+     * @param string $uid uid of the user
71
+     * @param string $gid gid of the group
72
+     * @return bool
73
+     *
74
+     * Checks whether the user is member of a group or not.
75
+     */
76
+    public function inGroup($uid, $gid) {
77
+        if(!$this->enabled) {
78
+            return false;
79
+        }
80
+        $cacheKey = 'inGroup'.$uid.':'.$gid;
81
+        $inGroup = $this->access->connection->getFromCache($cacheKey);
82
+        if(!is_null($inGroup)) {
83
+            return (bool)$inGroup;
84
+        }
85
+
86
+        $userDN = $this->access->username2dn($uid);
87
+
88
+        if(isset($this->cachedGroupMembers[$gid])) {
89
+            $isInGroup = in_array($userDN, $this->cachedGroupMembers[$gid]);
90
+            return $isInGroup;
91
+        }
92
+
93
+        $cacheKeyMembers = 'inGroup-members:'.$gid;
94
+        $members = $this->access->connection->getFromCache($cacheKeyMembers);
95
+        if(!is_null($members)) {
96
+            $this->cachedGroupMembers[$gid] = $members;
97
+            $isInGroup = in_array($userDN, $members);
98
+            $this->access->connection->writeToCache($cacheKey, $isInGroup);
99
+            return $isInGroup;
100
+        }
101
+
102
+        $groupDN = $this->access->groupname2dn($gid);
103
+        // just in case
104
+        if(!$groupDN || !$userDN) {
105
+            $this->access->connection->writeToCache($cacheKey, false);
106
+            return false;
107
+        }
108
+
109
+        //check primary group first
110
+        if($gid === $this->getUserPrimaryGroup($userDN)) {
111
+            $this->access->connection->writeToCache($cacheKey, true);
112
+            return true;
113
+        }
114
+
115
+        //usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
116
+        $members = $this->_groupMembers($groupDN);
117
+        $members = array_keys($members); // uids are returned as keys
118
+        if(!is_array($members) || count($members) === 0) {
119
+            $this->access->connection->writeToCache($cacheKey, false);
120
+            return false;
121
+        }
122
+
123
+        //extra work if we don't get back user DNs
124
+        if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
125
+            $dns = array();
126
+            $filterParts = array();
127
+            $bytes = 0;
128
+            foreach($members as $mid) {
129
+                $filter = str_replace('%uid', $mid, $this->access->connection->ldapLoginFilter);
130
+                $filterParts[] = $filter;
131
+                $bytes += strlen($filter);
132
+                if($bytes >= 9000000) {
133
+                    // AD has a default input buffer of 10 MB, we do not want
134
+                    // to take even the chance to exceed it
135
+                    $filter = $this->access->combineFilterWithOr($filterParts);
136
+                    $bytes = 0;
137
+                    $filterParts = array();
138
+                    $users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
139
+                    $dns = array_merge($dns, $users);
140
+                }
141
+            }
142
+            if(count($filterParts) > 0) {
143
+                $filter = $this->access->combineFilterWithOr($filterParts);
144
+                $users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
145
+                $dns = array_merge($dns, $users);
146
+            }
147
+            $members = $dns;
148
+        }
149
+
150
+        $isInGroup = in_array($userDN, $members);
151
+        $this->access->connection->writeToCache($cacheKey, $isInGroup);
152
+        $this->access->connection->writeToCache($cacheKeyMembers, $members);
153
+        $this->cachedGroupMembers[$gid] = $members;
154
+
155
+        return $isInGroup;
156
+    }
157
+
158
+    /**
159
+     * @param string $dnGroup
160
+     * @return array
161
+     *
162
+     * For a group that has user membership defined by an LDAP search url attribute returns the users
163
+     * that match the search url otherwise returns an empty array.
164
+     */
165
+    public function getDynamicGroupMembers($dnGroup) {
166
+        $dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
167
+
168
+        if (empty($dynamicGroupMemberURL)) {
169
+            return array();
170
+        }
171
+
172
+        $dynamicMembers = array();
173
+        $memberURLs = $this->access->readAttribute(
174
+            $dnGroup,
175
+            $dynamicGroupMemberURL,
176
+            $this->access->connection->ldapGroupFilter
177
+        );
178
+        if ($memberURLs !== false) {
179
+            // this group has the 'memberURL' attribute so this is a dynamic group
180
+            // example 1: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(o=HeadOffice)
181
+            // example 2: ldap:///cn=users,cn=accounts,dc=dcsubbase,dc=dcbase??one?(&(o=HeadOffice)(uidNumber>=500))
182
+            $pos = strpos($memberURLs[0], '(');
183
+            if ($pos !== false) {
184
+                $memberUrlFilter = substr($memberURLs[0], $pos);
185
+                $foundMembers = $this->access->searchUsers($memberUrlFilter,'dn');
186
+                $dynamicMembers = array();
187
+                foreach($foundMembers as $value) {
188
+                    $dynamicMembers[$value['dn'][0]] = 1;
189
+                }
190
+            } else {
191
+                \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
192
+                    'of group ' . $dnGroup, \OCP\Util::DEBUG);
193
+            }
194
+        }
195
+        return $dynamicMembers;
196
+    }
197
+
198
+    /**
199
+     * @param string $dnGroup
200
+     * @param array|null &$seen
201
+     * @return array|mixed|null
202
+     */
203
+    private function _groupMembers($dnGroup, &$seen = null) {
204
+        if ($seen === null) {
205
+            $seen = array();
206
+        }
207
+        $allMembers = array();
208
+        if (array_key_exists($dnGroup, $seen)) {
209
+            // avoid loops
210
+            return array();
211
+        }
212
+        // used extensively in cron job, caching makes sense for nested groups
213
+        $cacheKey = '_groupMembers'.$dnGroup;
214
+        $groupMembers = $this->access->connection->getFromCache($cacheKey);
215
+        if(!is_null($groupMembers)) {
216
+            return $groupMembers;
217
+        }
218
+        $seen[$dnGroup] = 1;
219
+        $members = $this->access->readAttribute($dnGroup, $this->access->connection->ldapGroupMemberAssocAttr,
220
+                                                $this->access->connection->ldapGroupFilter);
221
+        if (is_array($members)) {
222
+            foreach ($members as $memberDN) {
223
+                $allMembers[$memberDN] = 1;
224
+                $nestedGroups = $this->access->connection->ldapNestedGroups;
225
+                if (!empty($nestedGroups)) {
226
+                    $subMembers = $this->_groupMembers($memberDN, $seen);
227
+                    if ($subMembers) {
228
+                        $allMembers = array_merge($allMembers, $subMembers);
229
+                    }
230
+                }
231
+            }
232
+        }
233
+
234
+        $allMembers = array_merge($allMembers, $this->getDynamicGroupMembers($dnGroup));
235
+
236
+        $this->access->connection->writeToCache($cacheKey, $allMembers);
237
+        return $allMembers;
238
+    }
239
+
240
+    /**
241
+     * @param string $DN
242
+     * @param array|null &$seen
243
+     * @return array
244
+     */
245
+    private function _getGroupDNsFromMemberOf($DN, &$seen = null) {
246
+        if ($seen === null) {
247
+            $seen = array();
248
+        }
249
+        if (array_key_exists($DN, $seen)) {
250
+            // avoid loops
251
+            return array();
252
+        }
253
+        $seen[$DN] = 1;
254
+        $groups = $this->access->readAttribute($DN, 'memberOf');
255
+        if (!is_array($groups)) {
256
+            return array();
257
+        }
258
+        $groups = $this->access->groupsMatchFilter($groups);
259
+        $allGroups =  $groups;
260
+        $nestedGroups = $this->access->connection->ldapNestedGroups;
261
+        if (intval($nestedGroups) === 1) {
262
+            foreach ($groups as $group) {
263
+                $subGroups = $this->_getGroupDNsFromMemberOf($group, $seen);
264
+                $allGroups = array_merge($allGroups, $subGroups);
265
+            }
266
+        }
267
+        return $allGroups;
268
+    }
269
+
270
+    /**
271
+     * translates a gidNumber into an ownCloud internal name
272
+     * @param string $gid as given by gidNumber on POSIX LDAP
273
+     * @param string $dn a DN that belongs to the same domain as the group
274
+     * @return string|bool
275
+     */
276
+    public function gidNumber2Name($gid, $dn) {
277
+        $cacheKey = 'gidNumberToName';
278
+        $groupNames = $this->access->connection->getFromCache($cacheKey);
279
+        if(!is_null($groupNames) && isset($groupNames[$gid])) {
280
+            return $groupNames[$gid];
281
+        }
282
+
283
+        //we need to get the DN from LDAP
284
+        $filter = $this->access->combineFilterWithAnd([
285
+            $this->access->connection->ldapGroupFilter,
286
+            'objectClass=posixGroup',
287
+            $this->access->connection->ldapGidNumber . '=' . $gid
288
+        ]);
289
+        $result = $this->access->searchGroups($filter, array('dn'), 1);
290
+        if(empty($result)) {
291
+            return false;
292
+        }
293
+        $dn = $result[0]['dn'][0];
294
+
295
+        //and now the group name
296
+        //NOTE once we have separate ownCloud group IDs and group names we can
297
+        //directly read the display name attribute instead of the DN
298
+        $name = $this->access->dn2groupname($dn);
299
+
300
+        $this->access->connection->writeToCache($cacheKey, $name);
301
+
302
+        return $name;
303
+    }
304
+
305
+    /**
306
+     * returns the entry's gidNumber
307
+     * @param string $dn
308
+     * @param string $attribute
309
+     * @return string|bool
310
+     */
311
+    private function getEntryGidNumber($dn, $attribute) {
312
+        $value = $this->access->readAttribute($dn, $attribute);
313
+        if(is_array($value) && !empty($value)) {
314
+            return $value[0];
315
+        }
316
+        return false;
317
+    }
318
+
319
+    /**
320
+     * returns the group's primary ID
321
+     * @param string $dn
322
+     * @return string|bool
323
+     */
324
+    public function getGroupGidNumber($dn) {
325
+        return $this->getEntryGidNumber($dn, 'gidNumber');
326
+    }
327
+
328
+    /**
329
+     * returns the user's gidNumber
330
+     * @param string $dn
331
+     * @return string|bool
332
+     */
333
+    public function getUserGidNumber($dn) {
334
+        $gidNumber = false;
335
+        if($this->access->connection->hasGidNumber) {
336
+            $gidNumber = $this->getEntryGidNumber($dn, 'gidNumber');
337
+            if($gidNumber === false) {
338
+                $this->access->connection->hasGidNumber = false;
339
+            }
340
+        }
341
+        return $gidNumber;
342
+    }
343
+
344
+    /**
345
+     * returns a filter for a "users has specific gid" search or count operation
346
+     *
347
+     * @param string $groupDN
348
+     * @param string $search
349
+     * @return string
350
+     * @throws \Exception
351
+     */
352
+    private function prepareFilterForUsersHasGidNumber($groupDN, $search = '') {
353
+        $groupID = $this->getGroupGidNumber($groupDN);
354
+        if($groupID === false) {
355
+            throw new \Exception('Not a valid group');
356
+        }
357
+
358
+        $filterParts = [];
359
+        $filterParts[] = $this->access->getFilterForUserCount();
360
+        if ($search !== '') {
361
+            $filterParts[] = $this->access->getFilterPartForUserSearch($search);
362
+        }
363
+        $filterParts[] = $this->access->connection->ldapGidNumber .'=' . $groupID;
364
+
365
+        $filter = $this->access->combineFilterWithAnd($filterParts);
366
+
367
+        return $filter;
368
+    }
369
+
370
+    /**
371
+     * returns a list of users that have the given group as gid number
372
+     *
373
+     * @param string $groupDN
374
+     * @param string $search
375
+     * @param int $limit
376
+     * @param int $offset
377
+     * @return string[]
378
+     */
379
+    public function getUsersInGidNumber($groupDN, $search = '', $limit = -1, $offset = 0) {
380
+        try {
381
+            $filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search);
382
+            $users = $this->access->fetchListOfUsers(
383
+                $filter,
384
+                [$this->access->connection->ldapUserDisplayName, 'dn'],
385
+                $limit,
386
+                $offset
387
+            );
388
+            return $this->access->ownCloudUserNames($users);
389
+        } catch (\Exception $e) {
390
+            return [];
391
+        }
392
+    }
393
+
394
+    /**
395
+     * returns the number of users that have the given group as gid number
396
+     *
397
+     * @param string $groupDN
398
+     * @param string $search
399
+     * @param int $limit
400
+     * @param int $offset
401
+     * @return int
402
+     */
403
+    public function countUsersInGidNumber($groupDN, $search = '', $limit = -1, $offset = 0) {
404
+        try {
405
+            $filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search);
406
+            $users = $this->access->countUsers($filter, ['dn'], $limit, $offset);
407
+            return (int)$users;
408
+        } catch (\Exception $e) {
409
+            return 0;
410
+        }
411
+    }
412
+
413
+    /**
414
+     * gets the gidNumber of a user
415
+     * @param string $dn
416
+     * @return string
417
+     */
418
+    public function getUserGroupByGid($dn) {
419
+        $groupID = $this->getUserGidNumber($dn);
420
+        if($groupID !== false) {
421
+            $groupName = $this->gidNumber2Name($groupID, $dn);
422
+            if($groupName !== false) {
423
+                return $groupName;
424
+            }
425
+        }
426
+
427
+        return false;
428
+    }
429
+
430
+    /**
431
+     * translates a primary group ID into an ownCloud internal name
432
+     * @param string $gid as given by primaryGroupID on AD
433
+     * @param string $dn a DN that belongs to the same domain as the group
434
+     * @return string|bool
435
+     */
436
+    public function primaryGroupID2Name($gid, $dn) {
437
+        $cacheKey = 'primaryGroupIDtoName';
438
+        $groupNames = $this->access->connection->getFromCache($cacheKey);
439
+        if(!is_null($groupNames) && isset($groupNames[$gid])) {
440
+            return $groupNames[$gid];
441
+        }
442
+
443
+        $domainObjectSid = $this->access->getSID($dn);
444
+        if($domainObjectSid === false) {
445
+            return false;
446
+        }
447
+
448
+        //we need to get the DN from LDAP
449
+        $filter = $this->access->combineFilterWithAnd(array(
450
+            $this->access->connection->ldapGroupFilter,
451
+            'objectsid=' . $domainObjectSid . '-' . $gid
452
+        ));
453
+        $result = $this->access->searchGroups($filter, array('dn'), 1);
454
+        if(empty($result)) {
455
+            return false;
456
+        }
457
+        $dn = $result[0]['dn'][0];
458
+
459
+        //and now the group name
460
+        //NOTE once we have separate ownCloud group IDs and group names we can
461
+        //directly read the display name attribute instead of the DN
462
+        $name = $this->access->dn2groupname($dn);
463
+
464
+        $this->access->connection->writeToCache($cacheKey, $name);
465
+
466
+        return $name;
467
+    }
468
+
469
+    /**
470
+     * returns the entry's primary group ID
471
+     * @param string $dn
472
+     * @param string $attribute
473
+     * @return string|bool
474
+     */
475
+    private function getEntryGroupID($dn, $attribute) {
476
+        $value = $this->access->readAttribute($dn, $attribute);
477
+        if(is_array($value) && !empty($value)) {
478
+            return $value[0];
479
+        }
480
+        return false;
481
+    }
482
+
483
+    /**
484
+     * returns the group's primary ID
485
+     * @param string $dn
486
+     * @return string|bool
487
+     */
488
+    public function getGroupPrimaryGroupID($dn) {
489
+        return $this->getEntryGroupID($dn, 'primaryGroupToken');
490
+    }
491
+
492
+    /**
493
+     * returns the user's primary group ID
494
+     * @param string $dn
495
+     * @return string|bool
496
+     */
497
+    public function getUserPrimaryGroupIDs($dn) {
498
+        $primaryGroupID = false;
499
+        if($this->access->connection->hasPrimaryGroups) {
500
+            $primaryGroupID = $this->getEntryGroupID($dn, 'primaryGroupID');
501
+            if($primaryGroupID === false) {
502
+                $this->access->connection->hasPrimaryGroups = false;
503
+            }
504
+        }
505
+        return $primaryGroupID;
506
+    }
507
+
508
+    /**
509
+     * returns a filter for a "users in primary group" search or count operation
510
+     *
511
+     * @param string $groupDN
512
+     * @param string $search
513
+     * @return string
514
+     * @throws \Exception
515
+     */
516
+    private function prepareFilterForUsersInPrimaryGroup($groupDN, $search = '') {
517
+        $groupID = $this->getGroupPrimaryGroupID($groupDN);
518
+        if($groupID === false) {
519
+            throw new \Exception('Not a valid group');
520
+        }
521
+
522
+        $filterParts = [];
523
+        $filterParts[] = $this->access->getFilterForUserCount();
524
+        if ($search !== '') {
525
+            $filterParts[] = $this->access->getFilterPartForUserSearch($search);
526
+        }
527
+        $filterParts[] = 'primaryGroupID=' . $groupID;
528
+
529
+        $filter = $this->access->combineFilterWithAnd($filterParts);
530
+
531
+        return $filter;
532
+    }
533
+
534
+    /**
535
+     * returns a list of users that have the given group as primary group
536
+     *
537
+     * @param string $groupDN
538
+     * @param string $search
539
+     * @param int $limit
540
+     * @param int $offset
541
+     * @return string[]
542
+     */
543
+    public function getUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
544
+        try {
545
+            $filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
546
+            $users = $this->access->fetchListOfUsers(
547
+                $filter,
548
+                array($this->access->connection->ldapUserDisplayName, 'dn'),
549
+                $limit,
550
+                $offset
551
+            );
552
+            return $this->access->ownCloudUserNames($users);
553
+        } catch (\Exception $e) {
554
+            return array();
555
+        }
556
+    }
557
+
558
+    /**
559
+     * returns the number of users that have the given group as primary group
560
+     *
561
+     * @param string $groupDN
562
+     * @param string $search
563
+     * @param int $limit
564
+     * @param int $offset
565
+     * @return int
566
+     */
567
+    public function countUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
568
+        try {
569
+            $filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
570
+            $users = $this->access->countUsers($filter, array('dn'), $limit, $offset);
571
+            return (int)$users;
572
+        } catch (\Exception $e) {
573
+            return 0;
574
+        }
575
+    }
576
+
577
+    /**
578
+     * gets the primary group of a user
579
+     * @param string $dn
580
+     * @return string
581
+     */
582
+    public function getUserPrimaryGroup($dn) {
583
+        $groupID = $this->getUserPrimaryGroupIDs($dn);
584
+        if($groupID !== false) {
585
+            $groupName = $this->primaryGroupID2Name($groupID, $dn);
586
+            if($groupName !== false) {
587
+                return $groupName;
588
+            }
589
+        }
590
+
591
+        return false;
592
+    }
593
+
594
+    /**
595
+     * Get all groups a user belongs to
596
+     * @param string $uid Name of the user
597
+     * @return array with group names
598
+     *
599
+     * This function fetches all groups a user belongs to. It does not check
600
+     * if the user exists at all.
601
+     *
602
+     * This function includes groups based on dynamic group membership.
603
+     */
604
+    public function getUserGroups($uid) {
605
+        if(!$this->enabled) {
606
+            return array();
607
+        }
608
+        $cacheKey = 'getUserGroups'.$uid;
609
+        $userGroups = $this->access->connection->getFromCache($cacheKey);
610
+        if(!is_null($userGroups)) {
611
+            return $userGroups;
612
+        }
613
+        $userDN = $this->access->username2dn($uid);
614
+        if(!$userDN) {
615
+            $this->access->connection->writeToCache($cacheKey, array());
616
+            return array();
617
+        }
618
+
619
+        $groups = [];
620
+        $primaryGroup = $this->getUserPrimaryGroup($userDN);
621
+        $gidGroupName = $this->getUserGroupByGid($userDN);
622
+
623
+        $dynamicGroupMemberURL = strtolower($this->access->connection->ldapDynamicGroupMemberURL);
624
+
625
+        if (!empty($dynamicGroupMemberURL)) {
626
+            // look through dynamic groups to add them to the result array if needed
627
+            $groupsToMatch = $this->access->fetchListOfGroups(
628
+                $this->access->connection->ldapGroupFilter,array('dn',$dynamicGroupMemberURL));
629
+            foreach($groupsToMatch as $dynamicGroup) {
630
+                if (!array_key_exists($dynamicGroupMemberURL, $dynamicGroup)) {
631
+                    continue;
632
+                }
633
+                $pos = strpos($dynamicGroup[$dynamicGroupMemberURL][0], '(');
634
+                if ($pos !== false) {
635
+                    $memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0],$pos);
636
+                    // apply filter via ldap search to see if this user is in this
637
+                    // dynamic group
638
+                    $userMatch = $this->access->readAttribute(
639
+                        $userDN,
640
+                        $this->access->connection->ldapUserDisplayName,
641
+                        $memberUrlFilter
642
+                    );
643
+                    if ($userMatch !== false) {
644
+                        // match found so this user is in this group
645
+                        $groupName = $this->access->dn2groupname($dynamicGroup['dn'][0]);
646
+                        if(is_string($groupName)) {
647
+                            // be sure to never return false if the dn could not be
648
+                            // resolved to a name, for whatever reason.
649
+                            $groups[] = $groupName;
650
+                        }
651
+                    }
652
+                } else {
653
+                    \OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
654
+                        'of group ' . print_r($dynamicGroup, true), \OCP\Util::DEBUG);
655
+                }
656
+            }
657
+        }
658
+
659
+        // if possible, read out membership via memberOf. It's far faster than
660
+        // performing a search, which still is a fallback later.
661
+        if(intval($this->access->connection->hasMemberOfFilterSupport) === 1
662
+            && intval($this->access->connection->useMemberOfToDetectMembership) === 1
663
+        ) {
664
+            $groupDNs = $this->_getGroupDNsFromMemberOf($userDN);
665
+            if (is_array($groupDNs)) {
666
+                foreach ($groupDNs as $dn) {
667
+                    $groupName = $this->access->dn2groupname($dn);
668
+                    if(is_string($groupName)) {
669
+                        // be sure to never return false if the dn could not be
670
+                        // resolved to a name, for whatever reason.
671
+                        $groups[] = $groupName;
672
+                    }
673
+                }
674
+            }
675
+
676
+            if($primaryGroup !== false) {
677
+                $groups[] = $primaryGroup;
678
+            }
679
+            if($gidGroupName !== false) {
680
+                $groups[] = $gidGroupName;
681
+            }
682
+            $this->access->connection->writeToCache($cacheKey, $groups);
683
+            return $groups;
684
+        }
685
+
686
+        //uniqueMember takes DN, memberuid the uid, so we need to distinguish
687
+        if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
688
+            || (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member')
689
+        ) {
690
+            $uid = $userDN;
691
+        } else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
692
+            $result = $this->access->readAttribute($userDN, 'uid');
693
+            if ($result === false) {
694
+                \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '.
695
+                    $this->access->connection->ldapHost, \OCP\Util::DEBUG);
696
+            }
697
+            $uid = $result[0];
698
+        } else {
699
+            // just in case
700
+            $uid = $userDN;
701
+        }
702
+
703
+        if(isset($this->cachedGroupsByMember[$uid])) {
704
+            $groups = array_merge($groups, $this->cachedGroupsByMember[$uid]);
705
+        } else {
706
+            $groupsByMember = array_values($this->getGroupsByMember($uid));
707
+            $groupsByMember = $this->access->ownCloudGroupNames($groupsByMember);
708
+            $this->cachedGroupsByMember[$uid] = $groupsByMember;
709
+            $groups = array_merge($groups, $groupsByMember);
710
+        }
711
+
712
+        if($primaryGroup !== false) {
713
+            $groups[] = $primaryGroup;
714
+        }
715
+        if($gidGroupName !== false) {
716
+            $groups[] = $gidGroupName;
717
+        }
718
+
719
+        $groups = array_unique($groups, SORT_LOCALE_STRING);
720
+        $this->access->connection->writeToCache($cacheKey, $groups);
721
+
722
+        return $groups;
723
+    }
724
+
725
+    /**
726
+     * @param string $dn
727
+     * @param array|null &$seen
728
+     * @return array
729
+     */
730
+    private function getGroupsByMember($dn, &$seen = null) {
731
+        if ($seen === null) {
732
+            $seen = array();
733
+        }
734
+        $allGroups = array();
735
+        if (array_key_exists($dn, $seen)) {
736
+            // avoid loops
737
+            return array();
738
+        }
739
+        $seen[$dn] = true;
740
+        $filter = $this->access->combineFilterWithAnd(array(
741
+            $this->access->connection->ldapGroupFilter,
742
+            $this->access->connection->ldapGroupMemberAssocAttr.'='.$dn
743
+        ));
744
+        $groups = $this->access->fetchListOfGroups($filter,
745
+            array($this->access->connection->ldapGroupDisplayName, 'dn'));
746
+        if (is_array($groups)) {
747
+            foreach ($groups as $groupobj) {
748
+                $groupDN = $groupobj['dn'][0];
749
+                $allGroups[$groupDN] = $groupobj;
750
+                $nestedGroups = $this->access->connection->ldapNestedGroups;
751
+                if (!empty($nestedGroups)) {
752
+                    $supergroups = $this->getGroupsByMember($groupDN, $seen);
753
+                    if (is_array($supergroups) && (count($supergroups)>0)) {
754
+                        $allGroups = array_merge($allGroups, $supergroups);
755
+                    }
756
+                }
757
+            }
758
+        }
759
+        return $allGroups;
760
+    }
761
+
762
+    /**
763
+     * get a list of all users in a group
764
+     *
765
+     * @param string $gid
766
+     * @param string $search
767
+     * @param int $limit
768
+     * @param int $offset
769
+     * @return array with user ids
770
+     */
771
+    public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
772
+        if(!$this->enabled) {
773
+            return array();
774
+        }
775
+        if(!$this->groupExists($gid)) {
776
+            return array();
777
+        }
778
+        $search = $this->access->escapeFilterPart($search, true);
779
+        $cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
780
+        // check for cache of the exact query
781
+        $groupUsers = $this->access->connection->getFromCache($cacheKey);
782
+        if(!is_null($groupUsers)) {
783
+            return $groupUsers;
784
+        }
785
+
786
+        // check for cache of the query without limit and offset
787
+        $groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
788
+        if(!is_null($groupUsers)) {
789
+            $groupUsers = array_slice($groupUsers, $offset, $limit);
790
+            $this->access->connection->writeToCache($cacheKey, $groupUsers);
791
+            return $groupUsers;
792
+        }
793
+
794
+        if($limit === -1) {
795
+            $limit = null;
796
+        }
797
+        $groupDN = $this->access->groupname2dn($gid);
798
+        if(!$groupDN) {
799
+            // group couldn't be found, return empty resultset
800
+            $this->access->connection->writeToCache($cacheKey, array());
801
+            return array();
802
+        }
803
+
804
+        $primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset);
805
+        $members = array_keys($this->_groupMembers($groupDN));
806
+        if(!$members && empty($primaryUsers)) {
807
+            //in case users could not be retrieved, return empty result set
808
+            $this->access->connection->writeToCache($cacheKey, array());
809
+            return array();
810
+        }
811
+
812
+        $groupUsers = array();
813
+        $isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid');
814
+        $attrs = $this->access->userManager->getAttributes(true);
815
+        foreach($members as $member) {
816
+            if($isMemberUid) {
817
+                //we got uids, need to get their DNs to 'translate' them to user names
818
+                $filter = $this->access->combineFilterWithAnd(array(
819
+                    str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
820
+                    $this->access->getFilterPartForUserSearch($search)
821
+                ));
822
+                $ldap_users = $this->access->fetchListOfUsers($filter, $attrs, 1);
823
+                if(count($ldap_users) < 1) {
824
+                    continue;
825
+                }
826
+                $groupUsers[] = $this->access->dn2username($ldap_users[0]['dn'][0]);
827
+            } else {
828
+                //we got DNs, check if we need to filter by search or we can give back all of them
829
+                if ($search !== '') {
830
+                    if(!$this->access->readAttribute($member,
831
+                        $this->access->connection->ldapUserDisplayName,
832
+                        $this->access->getFilterPartForUserSearch($search))) {
833
+                        continue;
834
+                    }
835
+                }
836
+                // dn2username will also check if the users belong to the allowed base
837
+                if($ocname = $this->access->dn2username($member)) {
838
+                    $groupUsers[] = $ocname;
839
+                }
840
+            }
841
+        }
842
+
843
+        $groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
844
+        natsort($groupUsers);
845
+        $this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
846
+        $groupUsers = array_slice($groupUsers, $offset, $limit);
847
+
848
+
849
+        $this->access->connection->writeToCache($cacheKey, $groupUsers);
850
+
851
+        return $groupUsers;
852
+    }
853
+
854
+    /**
855
+     * returns the number of users in a group, who match the search term
856
+     * @param string $gid the internal group name
857
+     * @param string $search optional, a search string
858
+     * @return int|bool
859
+     */
860
+    public function countUsersInGroup($gid, $search = '') {
861
+        $cacheKey = 'countUsersInGroup-'.$gid.'-'.$search;
862
+        if(!$this->enabled || !$this->groupExists($gid)) {
863
+            return false;
864
+        }
865
+        $groupUsers = $this->access->connection->getFromCache($cacheKey);
866
+        if(!is_null($groupUsers)) {
867
+            return $groupUsers;
868
+        }
869
+
870
+        $groupDN = $this->access->groupname2dn($gid);
871
+        if(!$groupDN) {
872
+            // group couldn't be found, return empty result set
873
+            $this->access->connection->writeToCache($cacheKey, false);
874
+            return false;
875
+        }
876
+
877
+        $members = array_keys($this->_groupMembers($groupDN));
878
+        $primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, '');
879
+        if(!$members && $primaryUserCount === 0) {
880
+            //in case users could not be retrieved, return empty result set
881
+            $this->access->connection->writeToCache($cacheKey, false);
882
+            return false;
883
+        }
884
+
885
+        if ($search === '') {
886
+            $groupUsers = count($members) + $primaryUserCount;
887
+            $this->access->connection->writeToCache($cacheKey, $groupUsers);
888
+            return $groupUsers;
889
+        }
890
+        $search = $this->access->escapeFilterPart($search, true);
891
+        $isMemberUid =
892
+            (strtolower($this->access->connection->ldapGroupMemberAssocAttr)
893
+            === 'memberuid');
894
+
895
+        //we need to apply the search filter
896
+        //alternatives that need to be checked:
897
+        //a) get all users by search filter and array_intersect them
898
+        //b) a, but only when less than 1k 10k ?k users like it is
899
+        //c) put all DNs|uids in a LDAP filter, combine with the search string
900
+        //   and let it count.
901
+        //For now this is not important, because the only use of this method
902
+        //does not supply a search string
903
+        $groupUsers = array();
904
+        foreach($members as $member) {
905
+            if($isMemberUid) {
906
+                //we got uids, need to get their DNs to 'translate' them to user names
907
+                $filter = $this->access->combineFilterWithAnd(array(
908
+                    str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
909
+                    $this->access->getFilterPartForUserSearch($search)
910
+                ));
911
+                $ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1);
912
+                if(count($ldap_users) < 1) {
913
+                    continue;
914
+                }
915
+                $groupUsers[] = $this->access->dn2username($ldap_users[0]);
916
+            } else {
917
+                //we need to apply the search filter now
918
+                if(!$this->access->readAttribute($member,
919
+                    $this->access->connection->ldapUserDisplayName,
920
+                    $this->access->getFilterPartForUserSearch($search))) {
921
+                    continue;
922
+                }
923
+                // dn2username will also check if the users belong to the allowed base
924
+                if($ocname = $this->access->dn2username($member)) {
925
+                    $groupUsers[] = $ocname;
926
+                }
927
+            }
928
+        }
929
+
930
+        //and get users that have the group as primary
931
+        $primaryUsers = $this->countUsersInPrimaryGroup($groupDN, $search);
932
+
933
+        return count($groupUsers) + $primaryUsers;
934
+    }
935
+
936
+    /**
937
+     * get a list of all groups
938
+     *
939
+     * @param string $search
940
+     * @param $limit
941
+     * @param int $offset
942
+     * @return array with group names
943
+     *
944
+     * Returns a list with all groups (used by getGroups)
945
+     */
946
+    protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) {
947
+        if(!$this->enabled) {
948
+            return array();
949
+        }
950
+        $cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset;
951
+
952
+        //Check cache before driving unnecessary searches
953
+        \OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG);
954
+        $ldap_groups = $this->access->connection->getFromCache($cacheKey);
955
+        if(!is_null($ldap_groups)) {
956
+            return $ldap_groups;
957
+        }
958
+
959
+        // if we'd pass -1 to LDAP search, we'd end up in a Protocol
960
+        // error. With a limit of 0, we get 0 results. So we pass null.
961
+        if($limit <= 0) {
962
+            $limit = null;
963
+        }
964
+        $filter = $this->access->combineFilterWithAnd(array(
965
+            $this->access->connection->ldapGroupFilter,
966
+            $this->access->getFilterPartForGroupSearch($search)
967
+        ));
968
+        \OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, \OCP\Util::DEBUG);
969
+        $ldap_groups = $this->access->fetchListOfGroups($filter,
970
+                array($this->access->connection->ldapGroupDisplayName, 'dn'),
971
+                $limit,
972
+                $offset);
973
+        $ldap_groups = $this->access->ownCloudGroupNames($ldap_groups);
974
+
975
+        $this->access->connection->writeToCache($cacheKey, $ldap_groups);
976
+        return $ldap_groups;
977
+    }
978
+
979
+    /**
980
+     * get a list of all groups using a paged search
981
+     *
982
+     * @param string $search
983
+     * @param int $limit
984
+     * @param int $offset
985
+     * @return array with group names
986
+     *
987
+     * Returns a list with all groups
988
+     * Uses a paged search if available to override a
989
+     * server side search limit.
990
+     * (active directory has a limit of 1000 by default)
991
+     */
992
+    public function getGroups($search = '', $limit = -1, $offset = 0) {
993
+        if(!$this->enabled) {
994
+            return array();
995
+        }
996
+        $search = $this->access->escapeFilterPart($search, true);
997
+        $pagingSize = intval($this->access->connection->ldapPagingSize);
998
+        if (!$this->access->connection->hasPagedResultSupport || $pagingSize <= 0) {
999
+            return $this->getGroupsChunk($search, $limit, $offset);
1000
+        }
1001
+        $maxGroups = 100000; // limit max results (just for safety reasons)
1002
+        if ($limit > -1) {
1003
+            $overallLimit = min($limit + $offset, $maxGroups);
1004
+        } else {
1005
+            $overallLimit = $maxGroups;
1006
+        }
1007
+        $chunkOffset = $offset;
1008
+        $allGroups = array();
1009
+        while ($chunkOffset < $overallLimit) {
1010
+            $chunkLimit = min($pagingSize, $overallLimit - $chunkOffset);
1011
+            $ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset);
1012
+            $nread = count($ldapGroups);
1013
+            \OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', \OCP\Util::DEBUG);
1014
+            if ($nread) {
1015
+                $allGroups = array_merge($allGroups, $ldapGroups);
1016
+                $chunkOffset += $nread;
1017
+            }
1018
+            if ($nread < $chunkLimit) {
1019
+                break;
1020
+            }
1021
+        }
1022
+        return $allGroups;
1023
+    }
1024
+
1025
+    /**
1026
+     * @param string $group
1027
+     * @return bool
1028
+     */
1029
+    public function groupMatchesFilter($group) {
1030
+        return (strripos($group, $this->groupSearch) !== false);
1031
+    }
1032
+
1033
+    /**
1034
+     * check if a group exists
1035
+     * @param string $gid
1036
+     * @return bool
1037
+     */
1038
+    public function groupExists($gid) {
1039
+        $groupExists = $this->access->connection->getFromCache('groupExists'.$gid);
1040
+        if(!is_null($groupExists)) {
1041
+            return (bool)$groupExists;
1042
+        }
1043
+
1044
+        //getting dn, if false the group does not exist. If dn, it may be mapped
1045
+        //only, requires more checking.
1046
+        $dn = $this->access->groupname2dn($gid);
1047
+        if(!$dn) {
1048
+            $this->access->connection->writeToCache('groupExists'.$gid, false);
1049
+            return false;
1050
+        }
1051
+
1052
+        //if group really still exists, we will be able to read its objectclass
1053
+        if(!is_array($this->access->readAttribute($dn, ''))) {
1054
+            $this->access->connection->writeToCache('groupExists'.$gid, false);
1055
+            return false;
1056
+        }
1057
+
1058
+        $this->access->connection->writeToCache('groupExists'.$gid, true);
1059
+        return true;
1060
+    }
1061
+
1062
+    /**
1063
+     * Check if backend implements actions
1064
+     * @param int $actions bitwise-or'ed actions
1065
+     * @return boolean
1066
+     *
1067
+     * Returns the supported actions as int to be
1068
+     * compared with OC_USER_BACKEND_CREATE_USER etc.
1069
+     */
1070
+    public function implementsActions($actions) {
1071
+        return (bool)(\OC\Group\Backend::COUNT_USERS & $actions);
1072
+    }
1073
+
1074
+    /**
1075
+     * Return access for LDAP interaction.
1076
+     * @return Access instance of Access for LDAP interaction
1077
+     */
1078
+    public function getLDAPAccess() {
1079
+        return $this->access;
1080
+    }
1081 1081
 }
Please login to merge, or discard this patch.
Spacing   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@  discard block
 block discarded – undo
57 57
 		parent::__construct($access);
58 58
 		$filter = $this->access->connection->ldapGroupFilter;
59 59
 		$gassoc = $this->access->connection->ldapGroupMemberAssocAttr;
60
-		if(!empty($filter) && !empty($gassoc)) {
60
+		if (!empty($filter) && !empty($gassoc)) {
61 61
 			$this->enabled = true;
62 62
 		}
63 63
 
@@ -74,25 +74,25 @@  discard block
 block discarded – undo
74 74
 	 * Checks whether the user is member of a group or not.
75 75
 	 */
76 76
 	public function inGroup($uid, $gid) {
77
-		if(!$this->enabled) {
77
+		if (!$this->enabled) {
78 78
 			return false;
79 79
 		}
80 80
 		$cacheKey = 'inGroup'.$uid.':'.$gid;
81 81
 		$inGroup = $this->access->connection->getFromCache($cacheKey);
82
-		if(!is_null($inGroup)) {
83
-			return (bool)$inGroup;
82
+		if (!is_null($inGroup)) {
83
+			return (bool) $inGroup;
84 84
 		}
85 85
 
86 86
 		$userDN = $this->access->username2dn($uid);
87 87
 
88
-		if(isset($this->cachedGroupMembers[$gid])) {
88
+		if (isset($this->cachedGroupMembers[$gid])) {
89 89
 			$isInGroup = in_array($userDN, $this->cachedGroupMembers[$gid]);
90 90
 			return $isInGroup;
91 91
 		}
92 92
 
93 93
 		$cacheKeyMembers = 'inGroup-members:'.$gid;
94 94
 		$members = $this->access->connection->getFromCache($cacheKeyMembers);
95
-		if(!is_null($members)) {
95
+		if (!is_null($members)) {
96 96
 			$this->cachedGroupMembers[$gid] = $members;
97 97
 			$isInGroup = in_array($userDN, $members);
98 98
 			$this->access->connection->writeToCache($cacheKey, $isInGroup);
@@ -101,13 +101,13 @@  discard block
 block discarded – undo
101 101
 
102 102
 		$groupDN = $this->access->groupname2dn($gid);
103 103
 		// just in case
104
-		if(!$groupDN || !$userDN) {
104
+		if (!$groupDN || !$userDN) {
105 105
 			$this->access->connection->writeToCache($cacheKey, false);
106 106
 			return false;
107 107
 		}
108 108
 
109 109
 		//check primary group first
110
-		if($gid === $this->getUserPrimaryGroup($userDN)) {
110
+		if ($gid === $this->getUserPrimaryGroup($userDN)) {
111 111
 			$this->access->connection->writeToCache($cacheKey, true);
112 112
 			return true;
113 113
 		}
@@ -115,21 +115,21 @@  discard block
 block discarded – undo
115 115
 		//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
116 116
 		$members = $this->_groupMembers($groupDN);
117 117
 		$members = array_keys($members); // uids are returned as keys
118
-		if(!is_array($members) || count($members) === 0) {
118
+		if (!is_array($members) || count($members) === 0) {
119 119
 			$this->access->connection->writeToCache($cacheKey, false);
120 120
 			return false;
121 121
 		}
122 122
 
123 123
 		//extra work if we don't get back user DNs
124
-		if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
124
+		if (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
125 125
 			$dns = array();
126 126
 			$filterParts = array();
127 127
 			$bytes = 0;
128
-			foreach($members as $mid) {
128
+			foreach ($members as $mid) {
129 129
 				$filter = str_replace('%uid', $mid, $this->access->connection->ldapLoginFilter);
130 130
 				$filterParts[] = $filter;
131 131
 				$bytes += strlen($filter);
132
-				if($bytes >= 9000000) {
132
+				if ($bytes >= 9000000) {
133 133
 					// AD has a default input buffer of 10 MB, we do not want
134 134
 					// to take even the chance to exceed it
135 135
 					$filter = $this->access->combineFilterWithOr($filterParts);
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
 					$dns = array_merge($dns, $users);
140 140
 				}
141 141
 			}
142
-			if(count($filterParts) > 0) {
142
+			if (count($filterParts) > 0) {
143 143
 				$filter = $this->access->combineFilterWithOr($filterParts);
144 144
 				$users = $this->access->fetchListOfUsers($filter, 'dn', count($filterParts));
145 145
 				$dns = array_merge($dns, $users);
@@ -182,14 +182,14 @@  discard block
 block discarded – undo
182 182
 			$pos = strpos($memberURLs[0], '(');
183 183
 			if ($pos !== false) {
184 184
 				$memberUrlFilter = substr($memberURLs[0], $pos);
185
-				$foundMembers = $this->access->searchUsers($memberUrlFilter,'dn');
185
+				$foundMembers = $this->access->searchUsers($memberUrlFilter, 'dn');
186 186
 				$dynamicMembers = array();
187
-				foreach($foundMembers as $value) {
187
+				foreach ($foundMembers as $value) {
188 188
 					$dynamicMembers[$value['dn'][0]] = 1;
189 189
 				}
190 190
 			} else {
191 191
 				\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
192
-					'of group ' . $dnGroup, \OCP\Util::DEBUG);
192
+					'of group '.$dnGroup, \OCP\Util::DEBUG);
193 193
 			}
194 194
 		}
195 195
 		return $dynamicMembers;
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
 		// used extensively in cron job, caching makes sense for nested groups
213 213
 		$cacheKey = '_groupMembers'.$dnGroup;
214 214
 		$groupMembers = $this->access->connection->getFromCache($cacheKey);
215
-		if(!is_null($groupMembers)) {
215
+		if (!is_null($groupMembers)) {
216 216
 			return $groupMembers;
217 217
 		}
218 218
 		$seen[$dnGroup] = 1;
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
 			return array();
257 257
 		}
258 258
 		$groups = $this->access->groupsMatchFilter($groups);
259
-		$allGroups =  $groups;
259
+		$allGroups = $groups;
260 260
 		$nestedGroups = $this->access->connection->ldapNestedGroups;
261 261
 		if (intval($nestedGroups) === 1) {
262 262
 			foreach ($groups as $group) {
@@ -276,7 +276,7 @@  discard block
 block discarded – undo
276 276
 	public function gidNumber2Name($gid, $dn) {
277 277
 		$cacheKey = 'gidNumberToName';
278 278
 		$groupNames = $this->access->connection->getFromCache($cacheKey);
279
-		if(!is_null($groupNames) && isset($groupNames[$gid])) {
279
+		if (!is_null($groupNames) && isset($groupNames[$gid])) {
280 280
 			return $groupNames[$gid];
281 281
 		}
282 282
 
@@ -284,10 +284,10 @@  discard block
 block discarded – undo
284 284
 		$filter = $this->access->combineFilterWithAnd([
285 285
 			$this->access->connection->ldapGroupFilter,
286 286
 			'objectClass=posixGroup',
287
-			$this->access->connection->ldapGidNumber . '=' . $gid
287
+			$this->access->connection->ldapGidNumber.'='.$gid
288 288
 		]);
289 289
 		$result = $this->access->searchGroups($filter, array('dn'), 1);
290
-		if(empty($result)) {
290
+		if (empty($result)) {
291 291
 			return false;
292 292
 		}
293 293
 		$dn = $result[0]['dn'][0];
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
 	 */
311 311
 	private function getEntryGidNumber($dn, $attribute) {
312 312
 		$value = $this->access->readAttribute($dn, $attribute);
313
-		if(is_array($value) && !empty($value)) {
313
+		if (is_array($value) && !empty($value)) {
314 314
 			return $value[0];
315 315
 		}
316 316
 		return false;
@@ -332,9 +332,9 @@  discard block
 block discarded – undo
332 332
 	 */
333 333
 	public function getUserGidNumber($dn) {
334 334
 		$gidNumber = false;
335
-		if($this->access->connection->hasGidNumber) {
335
+		if ($this->access->connection->hasGidNumber) {
336 336
 			$gidNumber = $this->getEntryGidNumber($dn, 'gidNumber');
337
-			if($gidNumber === false) {
337
+			if ($gidNumber === false) {
338 338
 				$this->access->connection->hasGidNumber = false;
339 339
 			}
340 340
 		}
@@ -351,7 +351,7 @@  discard block
 block discarded – undo
351 351
 	 */
352 352
 	private function prepareFilterForUsersHasGidNumber($groupDN, $search = '') {
353 353
 		$groupID = $this->getGroupGidNumber($groupDN);
354
-		if($groupID === false) {
354
+		if ($groupID === false) {
355 355
 			throw new \Exception('Not a valid group');
356 356
 		}
357 357
 
@@ -360,7 +360,7 @@  discard block
 block discarded – undo
360 360
 		if ($search !== '') {
361 361
 			$filterParts[] = $this->access->getFilterPartForUserSearch($search);
362 362
 		}
363
-		$filterParts[] = $this->access->connection->ldapGidNumber .'=' . $groupID;
363
+		$filterParts[] = $this->access->connection->ldapGidNumber.'='.$groupID;
364 364
 
365 365
 		$filter = $this->access->combineFilterWithAnd($filterParts);
366 366
 
@@ -404,7 +404,7 @@  discard block
 block discarded – undo
404 404
 		try {
405 405
 			$filter = $this->prepareFilterForUsersHasGidNumber($groupDN, $search);
406 406
 			$users = $this->access->countUsers($filter, ['dn'], $limit, $offset);
407
-			return (int)$users;
407
+			return (int) $users;
408 408
 		} catch (\Exception $e) {
409 409
 			return 0;
410 410
 		}
@@ -417,9 +417,9 @@  discard block
 block discarded – undo
417 417
 	 */
418 418
 	public function getUserGroupByGid($dn) {
419 419
 		$groupID = $this->getUserGidNumber($dn);
420
-		if($groupID !== false) {
420
+		if ($groupID !== false) {
421 421
 			$groupName = $this->gidNumber2Name($groupID, $dn);
422
-			if($groupName !== false) {
422
+			if ($groupName !== false) {
423 423
 				return $groupName;
424 424
 			}
425 425
 		}
@@ -436,22 +436,22 @@  discard block
 block discarded – undo
436 436
 	public function primaryGroupID2Name($gid, $dn) {
437 437
 		$cacheKey = 'primaryGroupIDtoName';
438 438
 		$groupNames = $this->access->connection->getFromCache($cacheKey);
439
-		if(!is_null($groupNames) && isset($groupNames[$gid])) {
439
+		if (!is_null($groupNames) && isset($groupNames[$gid])) {
440 440
 			return $groupNames[$gid];
441 441
 		}
442 442
 
443 443
 		$domainObjectSid = $this->access->getSID($dn);
444
-		if($domainObjectSid === false) {
444
+		if ($domainObjectSid === false) {
445 445
 			return false;
446 446
 		}
447 447
 
448 448
 		//we need to get the DN from LDAP
449 449
 		$filter = $this->access->combineFilterWithAnd(array(
450 450
 			$this->access->connection->ldapGroupFilter,
451
-			'objectsid=' . $domainObjectSid . '-' . $gid
451
+			'objectsid='.$domainObjectSid.'-'.$gid
452 452
 		));
453 453
 		$result = $this->access->searchGroups($filter, array('dn'), 1);
454
-		if(empty($result)) {
454
+		if (empty($result)) {
455 455
 			return false;
456 456
 		}
457 457
 		$dn = $result[0]['dn'][0];
@@ -474,7 +474,7 @@  discard block
 block discarded – undo
474 474
 	 */
475 475
 	private function getEntryGroupID($dn, $attribute) {
476 476
 		$value = $this->access->readAttribute($dn, $attribute);
477
-		if(is_array($value) && !empty($value)) {
477
+		if (is_array($value) && !empty($value)) {
478 478
 			return $value[0];
479 479
 		}
480 480
 		return false;
@@ -496,9 +496,9 @@  discard block
 block discarded – undo
496 496
 	 */
497 497
 	public function getUserPrimaryGroupIDs($dn) {
498 498
 		$primaryGroupID = false;
499
-		if($this->access->connection->hasPrimaryGroups) {
499
+		if ($this->access->connection->hasPrimaryGroups) {
500 500
 			$primaryGroupID = $this->getEntryGroupID($dn, 'primaryGroupID');
501
-			if($primaryGroupID === false) {
501
+			if ($primaryGroupID === false) {
502 502
 				$this->access->connection->hasPrimaryGroups = false;
503 503
 			}
504 504
 		}
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
 	 */
516 516
 	private function prepareFilterForUsersInPrimaryGroup($groupDN, $search = '') {
517 517
 		$groupID = $this->getGroupPrimaryGroupID($groupDN);
518
-		if($groupID === false) {
518
+		if ($groupID === false) {
519 519
 			throw new \Exception('Not a valid group');
520 520
 		}
521 521
 
@@ -524,7 +524,7 @@  discard block
 block discarded – undo
524 524
 		if ($search !== '') {
525 525
 			$filterParts[] = $this->access->getFilterPartForUserSearch($search);
526 526
 		}
527
-		$filterParts[] = 'primaryGroupID=' . $groupID;
527
+		$filterParts[] = 'primaryGroupID='.$groupID;
528 528
 
529 529
 		$filter = $this->access->combineFilterWithAnd($filterParts);
530 530
 
@@ -568,7 +568,7 @@  discard block
 block discarded – undo
568 568
 		try {
569 569
 			$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
570 570
 			$users = $this->access->countUsers($filter, array('dn'), $limit, $offset);
571
-			return (int)$users;
571
+			return (int) $users;
572 572
 		} catch (\Exception $e) {
573 573
 			return 0;
574 574
 		}
@@ -581,9 +581,9 @@  discard block
 block discarded – undo
581 581
 	 */
582 582
 	public function getUserPrimaryGroup($dn) {
583 583
 		$groupID = $this->getUserPrimaryGroupIDs($dn);
584
-		if($groupID !== false) {
584
+		if ($groupID !== false) {
585 585
 			$groupName = $this->primaryGroupID2Name($groupID, $dn);
586
-			if($groupName !== false) {
586
+			if ($groupName !== false) {
587 587
 				return $groupName;
588 588
 			}
589 589
 		}
@@ -602,16 +602,16 @@  discard block
 block discarded – undo
602 602
 	 * This function includes groups based on dynamic group membership.
603 603
 	 */
604 604
 	public function getUserGroups($uid) {
605
-		if(!$this->enabled) {
605
+		if (!$this->enabled) {
606 606
 			return array();
607 607
 		}
608 608
 		$cacheKey = 'getUserGroups'.$uid;
609 609
 		$userGroups = $this->access->connection->getFromCache($cacheKey);
610
-		if(!is_null($userGroups)) {
610
+		if (!is_null($userGroups)) {
611 611
 			return $userGroups;
612 612
 		}
613 613
 		$userDN = $this->access->username2dn($uid);
614
-		if(!$userDN) {
614
+		if (!$userDN) {
615 615
 			$this->access->connection->writeToCache($cacheKey, array());
616 616
 			return array();
617 617
 		}
@@ -625,14 +625,14 @@  discard block
 block discarded – undo
625 625
 		if (!empty($dynamicGroupMemberURL)) {
626 626
 			// look through dynamic groups to add them to the result array if needed
627 627
 			$groupsToMatch = $this->access->fetchListOfGroups(
628
-				$this->access->connection->ldapGroupFilter,array('dn',$dynamicGroupMemberURL));
629
-			foreach($groupsToMatch as $dynamicGroup) {
628
+				$this->access->connection->ldapGroupFilter, array('dn', $dynamicGroupMemberURL));
629
+			foreach ($groupsToMatch as $dynamicGroup) {
630 630
 				if (!array_key_exists($dynamicGroupMemberURL, $dynamicGroup)) {
631 631
 					continue;
632 632
 				}
633 633
 				$pos = strpos($dynamicGroup[$dynamicGroupMemberURL][0], '(');
634 634
 				if ($pos !== false) {
635
-					$memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0],$pos);
635
+					$memberUrlFilter = substr($dynamicGroup[$dynamicGroupMemberURL][0], $pos);
636 636
 					// apply filter via ldap search to see if this user is in this
637 637
 					// dynamic group
638 638
 					$userMatch = $this->access->readAttribute(
@@ -643,7 +643,7 @@  discard block
 block discarded – undo
643 643
 					if ($userMatch !== false) {
644 644
 						// match found so this user is in this group
645 645
 						$groupName = $this->access->dn2groupname($dynamicGroup['dn'][0]);
646
-						if(is_string($groupName)) {
646
+						if (is_string($groupName)) {
647 647
 							// be sure to never return false if the dn could not be
648 648
 							// resolved to a name, for whatever reason.
649 649
 							$groups[] = $groupName;
@@ -651,21 +651,21 @@  discard block
 block discarded – undo
651 651
 					}
652 652
 				} else {
653 653
 					\OCP\Util::writeLog('user_ldap', 'No search filter found on member url '.
654
-						'of group ' . print_r($dynamicGroup, true), \OCP\Util::DEBUG);
654
+						'of group '.print_r($dynamicGroup, true), \OCP\Util::DEBUG);
655 655
 				}
656 656
 			}
657 657
 		}
658 658
 
659 659
 		// if possible, read out membership via memberOf. It's far faster than
660 660
 		// performing a search, which still is a fallback later.
661
-		if(intval($this->access->connection->hasMemberOfFilterSupport) === 1
661
+		if (intval($this->access->connection->hasMemberOfFilterSupport) === 1
662 662
 			&& intval($this->access->connection->useMemberOfToDetectMembership) === 1
663 663
 		) {
664 664
 			$groupDNs = $this->_getGroupDNsFromMemberOf($userDN);
665 665
 			if (is_array($groupDNs)) {
666 666
 				foreach ($groupDNs as $dn) {
667 667
 					$groupName = $this->access->dn2groupname($dn);
668
-					if(is_string($groupName)) {
668
+					if (is_string($groupName)) {
669 669
 						// be sure to never return false if the dn could not be
670 670
 						// resolved to a name, for whatever reason.
671 671
 						$groups[] = $groupName;
@@ -673,10 +673,10 @@  discard block
 block discarded – undo
673 673
 				}
674 674
 			}
675 675
 
676
-			if($primaryGroup !== false) {
676
+			if ($primaryGroup !== false) {
677 677
 				$groups[] = $primaryGroup;
678 678
 			}
679
-			if($gidGroupName !== false) {
679
+			if ($gidGroupName !== false) {
680 680
 				$groups[] = $gidGroupName;
681 681
 			}
682 682
 			$this->access->connection->writeToCache($cacheKey, $groups);
@@ -684,14 +684,14 @@  discard block
 block discarded – undo
684 684
 		}
685 685
 
686 686
 		//uniqueMember takes DN, memberuid the uid, so we need to distinguish
687
-		if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
687
+		if ((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
688 688
 			|| (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member')
689 689
 		) {
690 690
 			$uid = $userDN;
691
-		} else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
691
+		} else if (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
692 692
 			$result = $this->access->readAttribute($userDN, 'uid');
693 693
 			if ($result === false) {
694
-				\OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '.
694
+				\OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN '.$userDN.' on '.
695 695
 					$this->access->connection->ldapHost, \OCP\Util::DEBUG);
696 696
 			}
697 697
 			$uid = $result[0];
@@ -700,7 +700,7 @@  discard block
 block discarded – undo
700 700
 			$uid = $userDN;
701 701
 		}
702 702
 
703
-		if(isset($this->cachedGroupsByMember[$uid])) {
703
+		if (isset($this->cachedGroupsByMember[$uid])) {
704 704
 			$groups = array_merge($groups, $this->cachedGroupsByMember[$uid]);
705 705
 		} else {
706 706
 			$groupsByMember = array_values($this->getGroupsByMember($uid));
@@ -709,10 +709,10 @@  discard block
 block discarded – undo
709 709
 			$groups = array_merge($groups, $groupsByMember);
710 710
 		}
711 711
 
712
-		if($primaryGroup !== false) {
712
+		if ($primaryGroup !== false) {
713 713
 			$groups[] = $primaryGroup;
714 714
 		}
715
-		if($gidGroupName !== false) {
715
+		if ($gidGroupName !== false) {
716 716
 			$groups[] = $gidGroupName;
717 717
 		}
718 718
 
@@ -750,7 +750,7 @@  discard block
 block discarded – undo
750 750
 				$nestedGroups = $this->access->connection->ldapNestedGroups;
751 751
 				if (!empty($nestedGroups)) {
752 752
 					$supergroups = $this->getGroupsByMember($groupDN, $seen);
753
-					if (is_array($supergroups) && (count($supergroups)>0)) {
753
+					if (is_array($supergroups) && (count($supergroups) > 0)) {
754 754
 						$allGroups = array_merge($allGroups, $supergroups);
755 755
 					}
756 756
 				}
@@ -769,33 +769,33 @@  discard block
 block discarded – undo
769 769
 	 * @return array with user ids
770 770
 	 */
771 771
 	public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
772
-		if(!$this->enabled) {
772
+		if (!$this->enabled) {
773 773
 			return array();
774 774
 		}
775
-		if(!$this->groupExists($gid)) {
775
+		if (!$this->groupExists($gid)) {
776 776
 			return array();
777 777
 		}
778 778
 		$search = $this->access->escapeFilterPart($search, true);
779 779
 		$cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
780 780
 		// check for cache of the exact query
781 781
 		$groupUsers = $this->access->connection->getFromCache($cacheKey);
782
-		if(!is_null($groupUsers)) {
782
+		if (!is_null($groupUsers)) {
783 783
 			return $groupUsers;
784 784
 		}
785 785
 
786 786
 		// check for cache of the query without limit and offset
787 787
 		$groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
788
-		if(!is_null($groupUsers)) {
788
+		if (!is_null($groupUsers)) {
789 789
 			$groupUsers = array_slice($groupUsers, $offset, $limit);
790 790
 			$this->access->connection->writeToCache($cacheKey, $groupUsers);
791 791
 			return $groupUsers;
792 792
 		}
793 793
 
794
-		if($limit === -1) {
794
+		if ($limit === -1) {
795 795
 			$limit = null;
796 796
 		}
797 797
 		$groupDN = $this->access->groupname2dn($gid);
798
-		if(!$groupDN) {
798
+		if (!$groupDN) {
799 799
 			// group couldn't be found, return empty resultset
800 800
 			$this->access->connection->writeToCache($cacheKey, array());
801 801
 			return array();
@@ -803,7 +803,7 @@  discard block
 block discarded – undo
803 803
 
804 804
 		$primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset);
805 805
 		$members = array_keys($this->_groupMembers($groupDN));
806
-		if(!$members && empty($primaryUsers)) {
806
+		if (!$members && empty($primaryUsers)) {
807 807
 			//in case users could not be retrieved, return empty result set
808 808
 			$this->access->connection->writeToCache($cacheKey, array());
809 809
 			return array();
@@ -812,29 +812,29 @@  discard block
 block discarded – undo
812 812
 		$groupUsers = array();
813 813
 		$isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid');
814 814
 		$attrs = $this->access->userManager->getAttributes(true);
815
-		foreach($members as $member) {
816
-			if($isMemberUid) {
815
+		foreach ($members as $member) {
816
+			if ($isMemberUid) {
817 817
 				//we got uids, need to get their DNs to 'translate' them to user names
818 818
 				$filter = $this->access->combineFilterWithAnd(array(
819 819
 					str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
820 820
 					$this->access->getFilterPartForUserSearch($search)
821 821
 				));
822 822
 				$ldap_users = $this->access->fetchListOfUsers($filter, $attrs, 1);
823
-				if(count($ldap_users) < 1) {
823
+				if (count($ldap_users) < 1) {
824 824
 					continue;
825 825
 				}
826 826
 				$groupUsers[] = $this->access->dn2username($ldap_users[0]['dn'][0]);
827 827
 			} else {
828 828
 				//we got DNs, check if we need to filter by search or we can give back all of them
829 829
 				if ($search !== '') {
830
-					if(!$this->access->readAttribute($member,
830
+					if (!$this->access->readAttribute($member,
831 831
 						$this->access->connection->ldapUserDisplayName,
832 832
 						$this->access->getFilterPartForUserSearch($search))) {
833 833
 						continue;
834 834
 					}
835 835
 				}
836 836
 				// dn2username will also check if the users belong to the allowed base
837
-				if($ocname = $this->access->dn2username($member)) {
837
+				if ($ocname = $this->access->dn2username($member)) {
838 838
 					$groupUsers[] = $ocname;
839 839
 				}
840 840
 			}
@@ -859,16 +859,16 @@  discard block
 block discarded – undo
859 859
 	 */
860 860
 	public function countUsersInGroup($gid, $search = '') {
861 861
 		$cacheKey = 'countUsersInGroup-'.$gid.'-'.$search;
862
-		if(!$this->enabled || !$this->groupExists($gid)) {
862
+		if (!$this->enabled || !$this->groupExists($gid)) {
863 863
 			return false;
864 864
 		}
865 865
 		$groupUsers = $this->access->connection->getFromCache($cacheKey);
866
-		if(!is_null($groupUsers)) {
866
+		if (!is_null($groupUsers)) {
867 867
 			return $groupUsers;
868 868
 		}
869 869
 
870 870
 		$groupDN = $this->access->groupname2dn($gid);
871
-		if(!$groupDN) {
871
+		if (!$groupDN) {
872 872
 			// group couldn't be found, return empty result set
873 873
 			$this->access->connection->writeToCache($cacheKey, false);
874 874
 			return false;
@@ -876,7 +876,7 @@  discard block
 block discarded – undo
876 876
 
877 877
 		$members = array_keys($this->_groupMembers($groupDN));
878 878
 		$primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, '');
879
-		if(!$members && $primaryUserCount === 0) {
879
+		if (!$members && $primaryUserCount === 0) {
880 880
 			//in case users could not be retrieved, return empty result set
881 881
 			$this->access->connection->writeToCache($cacheKey, false);
882 882
 			return false;
@@ -901,27 +901,27 @@  discard block
 block discarded – undo
901 901
 		//For now this is not important, because the only use of this method
902 902
 		//does not supply a search string
903 903
 		$groupUsers = array();
904
-		foreach($members as $member) {
905
-			if($isMemberUid) {
904
+		foreach ($members as $member) {
905
+			if ($isMemberUid) {
906 906
 				//we got uids, need to get their DNs to 'translate' them to user names
907 907
 				$filter = $this->access->combineFilterWithAnd(array(
908 908
 					str_replace('%uid', $member, $this->access->connection->ldapLoginFilter),
909 909
 					$this->access->getFilterPartForUserSearch($search)
910 910
 				));
911 911
 				$ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1);
912
-				if(count($ldap_users) < 1) {
912
+				if (count($ldap_users) < 1) {
913 913
 					continue;
914 914
 				}
915 915
 				$groupUsers[] = $this->access->dn2username($ldap_users[0]);
916 916
 			} else {
917 917
 				//we need to apply the search filter now
918
-				if(!$this->access->readAttribute($member,
918
+				if (!$this->access->readAttribute($member,
919 919
 					$this->access->connection->ldapUserDisplayName,
920 920
 					$this->access->getFilterPartForUserSearch($search))) {
921 921
 					continue;
922 922
 				}
923 923
 				// dn2username will also check if the users belong to the allowed base
924
-				if($ocname = $this->access->dn2username($member)) {
924
+				if ($ocname = $this->access->dn2username($member)) {
925 925
 					$groupUsers[] = $ocname;
926 926
 				}
927 927
 			}
@@ -944,7 +944,7 @@  discard block
 block discarded – undo
944 944
 	 * Returns a list with all groups (used by getGroups)
945 945
 	 */
946 946
 	protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) {
947
-		if(!$this->enabled) {
947
+		if (!$this->enabled) {
948 948
 			return array();
949 949
 		}
950 950
 		$cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset;
@@ -952,13 +952,13 @@  discard block
 block discarded – undo
952 952
 		//Check cache before driving unnecessary searches
953 953
 		\OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG);
954 954
 		$ldap_groups = $this->access->connection->getFromCache($cacheKey);
955
-		if(!is_null($ldap_groups)) {
955
+		if (!is_null($ldap_groups)) {
956 956
 			return $ldap_groups;
957 957
 		}
958 958
 
959 959
 		// if we'd pass -1 to LDAP search, we'd end up in a Protocol
960 960
 		// error. With a limit of 0, we get 0 results. So we pass null.
961
-		if($limit <= 0) {
961
+		if ($limit <= 0) {
962 962
 			$limit = null;
963 963
 		}
964 964
 		$filter = $this->access->combineFilterWithAnd(array(
@@ -990,7 +990,7 @@  discard block
 block discarded – undo
990 990
 	 * (active directory has a limit of 1000 by default)
991 991
 	 */
992 992
 	public function getGroups($search = '', $limit = -1, $offset = 0) {
993
-		if(!$this->enabled) {
993
+		if (!$this->enabled) {
994 994
 			return array();
995 995
 		}
996 996
 		$search = $this->access->escapeFilterPart($search, true);
@@ -1037,20 +1037,20 @@  discard block
 block discarded – undo
1037 1037
 	 */
1038 1038
 	public function groupExists($gid) {
1039 1039
 		$groupExists = $this->access->connection->getFromCache('groupExists'.$gid);
1040
-		if(!is_null($groupExists)) {
1041
-			return (bool)$groupExists;
1040
+		if (!is_null($groupExists)) {
1041
+			return (bool) $groupExists;
1042 1042
 		}
1043 1043
 
1044 1044
 		//getting dn, if false the group does not exist. If dn, it may be mapped
1045 1045
 		//only, requires more checking.
1046 1046
 		$dn = $this->access->groupname2dn($gid);
1047
-		if(!$dn) {
1047
+		if (!$dn) {
1048 1048
 			$this->access->connection->writeToCache('groupExists'.$gid, false);
1049 1049
 			return false;
1050 1050
 		}
1051 1051
 
1052 1052
 		//if group really still exists, we will be able to read its objectclass
1053
-		if(!is_array($this->access->readAttribute($dn, ''))) {
1053
+		if (!is_array($this->access->readAttribute($dn, ''))) {
1054 1054
 			$this->access->connection->writeToCache('groupExists'.$gid, false);
1055 1055
 			return false;
1056 1056
 		}
@@ -1068,7 +1068,7 @@  discard block
 block discarded – undo
1068 1068
 	* compared with OC_USER_BACKEND_CREATE_USER etc.
1069 1069
 	*/
1070 1070
 	public function implementsActions($actions) {
1071
-		return (bool)(\OC\Group\Backend::COUNT_USERS & $actions);
1071
+		return (bool) (\OC\Group\Backend::COUNT_USERS & $actions);
1072 1072
 	}
1073 1073
 
1074 1074
 	/**
Please login to merge, or discard this patch.