@@ -52,574 +52,574 @@ |
||
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 | } |
@@ -59,72 +59,72 @@ |
||
59 | 59 | |
60 | 60 | <div id="ldapSettings"> |
61 | 61 | <ul> |
62 | - <li id="#ldapWizard1"><a href="#ldapWizard1"><?php p($l->t('Server'));?></a></li> |
|
63 | - <li id="#ldapWizard2"><a href="#ldapWizard2"><?php p($l->t('Users'));?></a></li> |
|
64 | - <li id="#ldapWizard3"><a href="#ldapWizard3"><?php p($l->t('Login Attributes'));?></a></li> |
|
65 | - <li id="#ldapWizard4"><a href="#ldapWizard4"><?php p($l->t('Groups'));?></a></li> |
|
66 | - <li class="ldapSettingsTabs"><a href="#ldapSettings-2"><?php p($l->t('Expert'));?></a></li> |
|
67 | - <li class="ldapSettingsTabs"><a href="#ldapSettings-1"><?php p($l->t('Advanced'));?></a></li> |
|
62 | + <li id="#ldapWizard1"><a href="#ldapWizard1"><?php p($l->t('Server')); ?></a></li> |
|
63 | + <li id="#ldapWizard2"><a href="#ldapWizard2"><?php p($l->t('Users')); ?></a></li> |
|
64 | + <li id="#ldapWizard3"><a href="#ldapWizard3"><?php p($l->t('Login Attributes')); ?></a></li> |
|
65 | + <li id="#ldapWizard4"><a href="#ldapWizard4"><?php p($l->t('Groups')); ?></a></li> |
|
66 | + <li class="ldapSettingsTabs"><a href="#ldapSettings-2"><?php p($l->t('Expert')); ?></a></li> |
|
67 | + <li class="ldapSettingsTabs"><a href="#ldapSettings-1"><?php p($l->t('Advanced')); ?></a></li> |
|
68 | 68 | </ul> |
69 | - <?php if(OCP\App::isEnabled('user_webdavauth')) { |
|
69 | + <?php if (OCP\App::isEnabled('user_webdavauth')) { |
|
70 | 70 | print_unescaped('<p class="ldapwarning">'.$l->t('<b>Warning:</b> Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behavior. Please ask your system administrator to disable one of them.').'</p>'); |
71 | 71 | } |
72 | - if(!function_exists('ldap_connect')) { |
|
72 | + if (!function_exists('ldap_connect')) { |
|
73 | 73 | print_unescaped('<p class="ldapwarning">'.$l->t('<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it.').'</p>'); |
74 | 74 | } |
75 | 75 | ?> |
76 | - <?php require_once(__DIR__ . '/part.wizard-server.php'); ?> |
|
77 | - <?php require_once(__DIR__ . '/part.wizard-userfilter.php'); ?> |
|
78 | - <?php require_once(__DIR__ . '/part.wizard-loginfilter.php'); ?> |
|
79 | - <?php require_once(__DIR__ . '/part.wizard-groupfilter.php'); ?> |
|
76 | + <?php require_once(__DIR__.'/part.wizard-server.php'); ?> |
|
77 | + <?php require_once(__DIR__.'/part.wizard-userfilter.php'); ?> |
|
78 | + <?php require_once(__DIR__.'/part.wizard-loginfilter.php'); ?> |
|
79 | + <?php require_once(__DIR__.'/part.wizard-groupfilter.php'); ?> |
|
80 | 80 | <fieldset id="ldapSettings-1"> |
81 | 81 | <div id="ldapAdvancedAccordion"> |
82 | - <h3><?php p($l->t('Connection Settings'));?></h3> |
|
82 | + <h3><?php p($l->t('Connection Settings')); ?></h3> |
|
83 | 83 | <div> |
84 | - <p><label for="ldap_configuration_active"><?php p($l->t('Configuration Active'));?></label><input type="checkbox" id="ldap_configuration_active" name="ldap_configuration_active" value="1" data-default="<?php p($_['ldap_configuration_active_default']); ?>" title="<?php p($l->t('When unchecked, this configuration will be skipped.'));?>" /></p> |
|
85 | - <p><label for="ldap_backup_host"><?php p($l->t('Backup (Replica) Host'));?></label><input type="text" id="ldap_backup_host" name="ldap_backup_host" data-default="<?php p($_['ldap_backup_host_default']); ?>" title="<?php p($l->t('Give an optional backup host. It must be a replica of the main LDAP/AD server.'));?>"></p> |
|
86 | - <p><label for="ldap_backup_port"><?php p($l->t('Backup (Replica) Port'));?></label><input type="number" id="ldap_backup_port" name="ldap_backup_port" data-default="<?php p($_['ldap_backup_port_default']); ?>" /></p> |
|
87 | - <p><label for="ldap_override_main_server"><?php p($l->t('Disable Main Server'));?></label><input type="checkbox" id="ldap_override_main_server" name="ldap_override_main_server" value="1" data-default="<?php p($_['ldap_override_main_server_default']); ?>" title="<?php p($l->t('Only connect to the replica server.'));?>" /></p> |
|
88 | - <p><label for="ldap_turn_off_cert_check"><?php p($l->t('Turn off SSL certificate validation.'));?></label><input type="checkbox" id="ldap_turn_off_cert_check" name="ldap_turn_off_cert_check" title="<?php p($l->t('Not recommended, use it for testing only! If connection only works with this option, import the LDAP server\'s SSL certificate in your %s server.', $theme->getName() ));?>" data-default="<?php p($_['ldap_turn_off_cert_check_default']); ?>" value="1"><br/></p> |
|
89 | - <p><label for="ldap_cache_ttl"><?php p($l->t('Cache Time-To-Live'));?></label><input type="number" id="ldap_cache_ttl" name="ldap_cache_ttl" title="<?php p($l->t('in seconds. A change empties the cache.'));?>" data-default="<?php p($_['ldap_cache_ttl_default']); ?>" /></p> |
|
84 | + <p><label for="ldap_configuration_active"><?php p($l->t('Configuration Active')); ?></label><input type="checkbox" id="ldap_configuration_active" name="ldap_configuration_active" value="1" data-default="<?php p($_['ldap_configuration_active_default']); ?>" title="<?php p($l->t('When unchecked, this configuration will be skipped.')); ?>" /></p> |
|
85 | + <p><label for="ldap_backup_host"><?php p($l->t('Backup (Replica) Host')); ?></label><input type="text" id="ldap_backup_host" name="ldap_backup_host" data-default="<?php p($_['ldap_backup_host_default']); ?>" title="<?php p($l->t('Give an optional backup host. It must be a replica of the main LDAP/AD server.')); ?>"></p> |
|
86 | + <p><label for="ldap_backup_port"><?php p($l->t('Backup (Replica) Port')); ?></label><input type="number" id="ldap_backup_port" name="ldap_backup_port" data-default="<?php p($_['ldap_backup_port_default']); ?>" /></p> |
|
87 | + <p><label for="ldap_override_main_server"><?php p($l->t('Disable Main Server')); ?></label><input type="checkbox" id="ldap_override_main_server" name="ldap_override_main_server" value="1" data-default="<?php p($_['ldap_override_main_server_default']); ?>" title="<?php p($l->t('Only connect to the replica server.')); ?>" /></p> |
|
88 | + <p><label for="ldap_turn_off_cert_check"><?php p($l->t('Turn off SSL certificate validation.')); ?></label><input type="checkbox" id="ldap_turn_off_cert_check" name="ldap_turn_off_cert_check" title="<?php p($l->t('Not recommended, use it for testing only! If connection only works with this option, import the LDAP server\'s SSL certificate in your %s server.', $theme->getName())); ?>" data-default="<?php p($_['ldap_turn_off_cert_check_default']); ?>" value="1"><br/></p> |
|
89 | + <p><label for="ldap_cache_ttl"><?php p($l->t('Cache Time-To-Live')); ?></label><input type="number" id="ldap_cache_ttl" name="ldap_cache_ttl" title="<?php p($l->t('in seconds. A change empties the cache.')); ?>" data-default="<?php p($_['ldap_cache_ttl_default']); ?>" /></p> |
|
90 | 90 | </div> |
91 | - <h3><?php p($l->t('Directory Settings'));?></h3> |
|
91 | + <h3><?php p($l->t('Directory Settings')); ?></h3> |
|
92 | 92 | <div> |
93 | - <p><label for="ldap_display_name"><?php p($l->t('User Display Name Field'));?></label><input type="text" id="ldap_display_name" name="ldap_display_name" data-default="<?php p($_['ldap_display_name_default']); ?>" title="<?php p($l->t('The LDAP attribute to use to generate the user\'s display name.'));?>" /></p> |
|
94 | - <p><label for="ldap_user_display_name_2"><?php p($l->t('2nd User Display Name Field'));?></label><input type="text" id="ldap_user_display_name_2" name="ldap_user_display_name_2" data-default="<?php p($_['ldap_user_display_name_2_default']); ?>" title="<?php p($l->t('Optional. An LDAP attribute to be added to the display name in brackets. Results in e.g. »John Doe ([email protected])«.'));?>" /></p> |
|
95 | - <p><label for="ldap_base_users"><?php p($l->t('Base User Tree'));?></label><textarea id="ldap_base_users" name="ldap_base_users" placeholder="<?php p($l->t('One User Base DN per line'));?>" data-default="<?php p($_['ldap_base_users_default']); ?>" title="<?php p($l->t('Base User Tree'));?>"></textarea></p> |
|
96 | - <p><label for="ldap_attributes_for_user_search"><?php p($l->t('User Search Attributes'));?></label><textarea id="ldap_attributes_for_user_search" name="ldap_attributes_for_user_search" placeholder="<?php p($l->t('Optional; one attribute per line'));?>" data-default="<?php p($_['ldap_attributes_for_user_search_default']); ?>" title="<?php p($l->t('User Search Attributes'));?>"></textarea></p> |
|
97 | - <p><label for="ldap_group_display_name"><?php p($l->t('Group Display Name Field'));?></label><input type="text" id="ldap_group_display_name" name="ldap_group_display_name" data-default="<?php p($_['ldap_group_display_name_default']); ?>" title="<?php p($l->t('The LDAP attribute to use to generate the groups\'s display name.'));?>" /></p> |
|
98 | - <p><label for="ldap_base_groups"><?php p($l->t('Base Group Tree'));?></label><textarea id="ldap_base_groups" name="ldap_base_groups" placeholder="<?php p($l->t('One Group Base DN per line'));?>" data-default="<?php p($_['ldap_base_groups_default']); ?>" title="<?php p($l->t('Base Group Tree'));?>"></textarea></p> |
|
99 | - <p><label for="ldap_attributes_for_group_search"><?php p($l->t('Group Search Attributes'));?></label><textarea id="ldap_attributes_for_group_search" name="ldap_attributes_for_group_search" placeholder="<?php p($l->t('Optional; one attribute per line'));?>" data-default="<?php p($_['ldap_attributes_for_group_search_default']); ?>" title="<?php p($l->t('Group Search Attributes'));?>"></textarea></p> |
|
100 | - <p><label for="ldap_group_member_assoc_attribute"><?php p($l->t('Group-Member association'));?></label><select id="ldap_group_member_assoc_attribute" name="ldap_group_member_assoc_attribute" data-default="<?php p($_['ldap_group_member_assoc_attribute_default']); ?>" ><option value="uniqueMember"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'uniqueMember')) p(' selected'); ?>>uniqueMember</option><option value="memberUid"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'memberUid')) p(' selected'); ?>>memberUid</option><option value="member"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'member')) p(' selected'); ?>>member (AD)</option><option value="gidNumber"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'gidNumber')) p(' selected'); ?>>gidNumber</option></select></p> <p><label for="ldap_dynamic_group_member_url"><?php p($l->t('Dynamic Group Member URL'));?></label><input type="text" id="ldap_dynamic_group_member_url" name="ldap_dynamic_group_member_url" title="<?php p($l->t('The LDAP attribute that on group objects contains an LDAP search URL that determines what objects belong to the group. (An empty setting disables dynamic group membership functionality.)'));?>" data-default="<?php p($_['ldap_dynamic_group_member_url_default']); ?>" /></p> |
|
101 | - <p><label for="ldap_nested_groups"><?php p($l->t('Nested Groups'));?></label><input type="checkbox" id="ldap_nested_groups" name="ldap_nested_groups" value="1" data-default="<?php p($_['ldap_nested_groups_default']); ?>" title="<?php p($l->t('When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)'));?>" /></p> |
|
102 | - <p><label for="ldap_paging_size"><?php p($l->t('Paging chunksize'));?></label><input type="number" id="ldap_paging_size" name="ldap_paging_size" title="<?php p($l->t('Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)'));?>" data-default="<?php p($_['ldap_paging_size_default']); ?>" /></p> |
|
103 | - <p><label for="ldap_turn_on_pwd_change"><?php p($l->t('Enable LDAP password changes per user'));?></label><span class="inlinetable"><span class="tablerow left"><input type="checkbox" id="ldap_turn_on_pwd_change" name="ldap_turn_on_pwd_change" value="1" data-default="<?php p($_['ldap_turn_on_pwd_change_default']); ?>" title="<?php p($l->t('Allow LDAP users to change their password and allow Super Administrators and Group Administrators to change the password of their LDAP users. Only works when access control policies are configured accordingly on the LDAP server. As passwords are sent in plaintext to the LDAP server, transport encryption must be used and password hashing should be configured on the LDAP server.'));?>" /><span class="tablecell"><?php p($l->t('(New password is sent as plain text to LDAP)'));?></span></span> |
|
93 | + <p><label for="ldap_display_name"><?php p($l->t('User Display Name Field')); ?></label><input type="text" id="ldap_display_name" name="ldap_display_name" data-default="<?php p($_['ldap_display_name_default']); ?>" title="<?php p($l->t('The LDAP attribute to use to generate the user\'s display name.')); ?>" /></p> |
|
94 | + <p><label for="ldap_user_display_name_2"><?php p($l->t('2nd User Display Name Field')); ?></label><input type="text" id="ldap_user_display_name_2" name="ldap_user_display_name_2" data-default="<?php p($_['ldap_user_display_name_2_default']); ?>" title="<?php p($l->t('Optional. An LDAP attribute to be added to the display name in brackets. Results in e.g. »John Doe ([email protected])«.')); ?>" /></p> |
|
95 | + <p><label for="ldap_base_users"><?php p($l->t('Base User Tree')); ?></label><textarea id="ldap_base_users" name="ldap_base_users" placeholder="<?php p($l->t('One User Base DN per line')); ?>" data-default="<?php p($_['ldap_base_users_default']); ?>" title="<?php p($l->t('Base User Tree')); ?>"></textarea></p> |
|
96 | + <p><label for="ldap_attributes_for_user_search"><?php p($l->t('User Search Attributes')); ?></label><textarea id="ldap_attributes_for_user_search" name="ldap_attributes_for_user_search" placeholder="<?php p($l->t('Optional; one attribute per line')); ?>" data-default="<?php p($_['ldap_attributes_for_user_search_default']); ?>" title="<?php p($l->t('User Search Attributes')); ?>"></textarea></p> |
|
97 | + <p><label for="ldap_group_display_name"><?php p($l->t('Group Display Name Field')); ?></label><input type="text" id="ldap_group_display_name" name="ldap_group_display_name" data-default="<?php p($_['ldap_group_display_name_default']); ?>" title="<?php p($l->t('The LDAP attribute to use to generate the groups\'s display name.')); ?>" /></p> |
|
98 | + <p><label for="ldap_base_groups"><?php p($l->t('Base Group Tree')); ?></label><textarea id="ldap_base_groups" name="ldap_base_groups" placeholder="<?php p($l->t('One Group Base DN per line')); ?>" data-default="<?php p($_['ldap_base_groups_default']); ?>" title="<?php p($l->t('Base Group Tree')); ?>"></textarea></p> |
|
99 | + <p><label for="ldap_attributes_for_group_search"><?php p($l->t('Group Search Attributes')); ?></label><textarea id="ldap_attributes_for_group_search" name="ldap_attributes_for_group_search" placeholder="<?php p($l->t('Optional; one attribute per line')); ?>" data-default="<?php p($_['ldap_attributes_for_group_search_default']); ?>" title="<?php p($l->t('Group Search Attributes')); ?>"></textarea></p> |
|
100 | + <p><label for="ldap_group_member_assoc_attribute"><?php p($l->t('Group-Member association')); ?></label><select id="ldap_group_member_assoc_attribute" name="ldap_group_member_assoc_attribute" data-default="<?php p($_['ldap_group_member_assoc_attribute_default']); ?>" ><option value="uniqueMember"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'uniqueMember')) p(' selected'); ?>>uniqueMember</option><option value="memberUid"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'memberUid')) p(' selected'); ?>>memberUid</option><option value="member"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'member')) p(' selected'); ?>>member (AD)</option><option value="gidNumber"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'gidNumber')) p(' selected'); ?>>gidNumber</option></select></p> <p><label for="ldap_dynamic_group_member_url"><?php p($l->t('Dynamic Group Member URL')); ?></label><input type="text" id="ldap_dynamic_group_member_url" name="ldap_dynamic_group_member_url" title="<?php p($l->t('The LDAP attribute that on group objects contains an LDAP search URL that determines what objects belong to the group. (An empty setting disables dynamic group membership functionality.)')); ?>" data-default="<?php p($_['ldap_dynamic_group_member_url_default']); ?>" /></p> |
|
101 | + <p><label for="ldap_nested_groups"><?php p($l->t('Nested Groups')); ?></label><input type="checkbox" id="ldap_nested_groups" name="ldap_nested_groups" value="1" data-default="<?php p($_['ldap_nested_groups_default']); ?>" title="<?php p($l->t('When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)')); ?>" /></p> |
|
102 | + <p><label for="ldap_paging_size"><?php p($l->t('Paging chunksize')); ?></label><input type="number" id="ldap_paging_size" name="ldap_paging_size" title="<?php p($l->t('Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)')); ?>" data-default="<?php p($_['ldap_paging_size_default']); ?>" /></p> |
|
103 | + <p><label for="ldap_turn_on_pwd_change"><?php p($l->t('Enable LDAP password changes per user')); ?></label><span class="inlinetable"><span class="tablerow left"><input type="checkbox" id="ldap_turn_on_pwd_change" name="ldap_turn_on_pwd_change" value="1" data-default="<?php p($_['ldap_turn_on_pwd_change_default']); ?>" title="<?php p($l->t('Allow LDAP users to change their password and allow Super Administrators and Group Administrators to change the password of their LDAP users. Only works when access control policies are configured accordingly on the LDAP server. As passwords are sent in plaintext to the LDAP server, transport encryption must be used and password hashing should be configured on the LDAP server.')); ?>" /><span class="tablecell"><?php p($l->t('(New password is sent as plain text to LDAP)')); ?></span></span> |
|
104 | 104 | </span><br/></p> |
105 | - <p><label for="ldap_default_ppolicy_dn"><?php p($l->t('Default password policy DN'));?></label><input type="text" id="ldap_default_ppolicy_dn" name="ldap_default_ppolicy_dn" title="<?php p($l->t('The DN of a default password policy that will be used for password expiry handling. Works only when LDAP password changes per user are enabled and is only supported by OpenLDAP. Leave empty to disable password expiry handling.'));?>" data-default="<?php p($_['ldap_default_ppolicy_dn_default']); ?>" /></p> |
|
105 | + <p><label for="ldap_default_ppolicy_dn"><?php p($l->t('Default password policy DN')); ?></label><input type="text" id="ldap_default_ppolicy_dn" name="ldap_default_ppolicy_dn" title="<?php p($l->t('The DN of a default password policy that will be used for password expiry handling. Works only when LDAP password changes per user are enabled and is only supported by OpenLDAP. Leave empty to disable password expiry handling.')); ?>" data-default="<?php p($_['ldap_default_ppolicy_dn_default']); ?>" /></p> |
|
106 | 106 | </div> |
107 | - <h3><?php p($l->t('Special Attributes'));?></h3> |
|
107 | + <h3><?php p($l->t('Special Attributes')); ?></h3> |
|
108 | 108 | <div> |
109 | - <p><label for="ldap_quota_attr"><?php p($l->t('Quota Field'));?></label><input type="text" id="ldap_quota_attr" name="ldap_quota_attr" data-default="<?php p($_['ldap_quota_attr_default']); ?>" title="<?php p($l->t('Leave empty for user\'s default quota. Otherwise, specify an LDAP/AD attribute.'));?>" /></p> |
|
110 | - <p><label for="ldap_quota_def"><?php p($l->t('Quota Default'));?></label><input type="text" id="ldap_quota_def" name="ldap_quota_def" data-default="<?php p($_['ldap_quota_def_default']); ?>" title="<?php p($l->t('Override default quota for LDAP users who do not have a quota set in the Quota Field.'));?>" /></p> |
|
111 | - <p><label for="ldap_email_attr"><?php p($l->t('Email Field'));?></label><input type="text" id="ldap_email_attr" name="ldap_email_attr" data-default="<?php p($_['ldap_email_attr_default']); ?>" title="<?php p($l->t('Set the user\'s email from their LDAP attribute. Leave it empty for default behaviour.'));?>" /></p> |
|
112 | - <p><label for="home_folder_naming_rule"><?php p($l->t('User Home Folder Naming Rule'));?></label><input type="text" id="home_folder_naming_rule" name="home_folder_naming_rule" title="<?php p($l->t('Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute.'));?>" data-default="<?php p($_['home_folder_naming_rule_default']); ?>" /></p> |
|
109 | + <p><label for="ldap_quota_attr"><?php p($l->t('Quota Field')); ?></label><input type="text" id="ldap_quota_attr" name="ldap_quota_attr" data-default="<?php p($_['ldap_quota_attr_default']); ?>" title="<?php p($l->t('Leave empty for user\'s default quota. Otherwise, specify an LDAP/AD attribute.')); ?>" /></p> |
|
110 | + <p><label for="ldap_quota_def"><?php p($l->t('Quota Default')); ?></label><input type="text" id="ldap_quota_def" name="ldap_quota_def" data-default="<?php p($_['ldap_quota_def_default']); ?>" title="<?php p($l->t('Override default quota for LDAP users who do not have a quota set in the Quota Field.')); ?>" /></p> |
|
111 | + <p><label for="ldap_email_attr"><?php p($l->t('Email Field')); ?></label><input type="text" id="ldap_email_attr" name="ldap_email_attr" data-default="<?php p($_['ldap_email_attr_default']); ?>" title="<?php p($l->t('Set the user\'s email from their LDAP attribute. Leave it empty for default behaviour.')); ?>" /></p> |
|
112 | + <p><label for="home_folder_naming_rule"><?php p($l->t('User Home Folder Naming Rule')); ?></label><input type="text" id="home_folder_naming_rule" name="home_folder_naming_rule" title="<?php p($l->t('Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute.')); ?>" data-default="<?php p($_['home_folder_naming_rule_default']); ?>" /></p> |
|
113 | 113 | </div> |
114 | 114 | </div> |
115 | 115 | <?php print_unescaped($_['settingControls']); ?> |
116 | 116 | </fieldset> |
117 | 117 | <fieldset id="ldapSettings-2"> |
118 | - <p><strong><?php p($l->t('Internal Username'));?></strong></p> |
|
119 | - <p class="ldapIndent"><?php p($l->t('By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users.'));?></p> |
|
120 | - <p class="ldapIndent"><label for="ldap_expert_username_attr"><?php p($l->t('Internal Username Attribute:'));?></label><input type="text" id="ldap_expert_username_attr" name="ldap_expert_username_attr" data-default="<?php p($_['ldap_expert_username_attr_default']); ?>" /></p> |
|
121 | - <p><strong><?php p($l->t('Override UUID detection'));?></strong></p> |
|
122 | - <p class="ldapIndent"><?php p($l->t('By default, the UUID attribute is automatically detected. The UUID attribute is used to doubtlessly identify LDAP users and groups. Also, the internal username will be created based on the UUID, if not specified otherwise above. You can override the setting and pass an attribute of your choice. You must make sure that the attribute of your choice can be fetched for both users and groups and it is unique. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users and groups.'));?></p> |
|
123 | - <p class="ldapIndent"><label for="ldap_expert_uuid_user_attr"><?php p($l->t('UUID Attribute for Users:'));?></label><input type="text" id="ldap_expert_uuid_user_attr" name="ldap_expert_uuid_user_attr" data-default="<?php p($_['ldap_expert_uuid_user_attr_default']); ?>" /></p> |
|
124 | - <p class="ldapIndent"><label for="ldap_expert_uuid_group_attr"><?php p($l->t('UUID Attribute for Groups:'));?></label><input type="text" id="ldap_expert_uuid_group_attr" name="ldap_expert_uuid_group_attr" data-default="<?php p($_['ldap_expert_uuid_group_attr_default']); ?>" /></p> |
|
125 | - <p><strong><?php p($l->t('Username-LDAP User Mapping'));?></strong></p> |
|
126 | - <p class="ldapIndent"><?php p($l->t('Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have an internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage.'));?></p> |
|
127 | - <p class="ldapIndent"><button type="button" id="ldap_action_clear_user_mappings" name="ldap_action_clear_user_mappings"><?php p($l->t('Clear Username-LDAP User Mapping'));?></button><br/><button type="button" id="ldap_action_clear_group_mappings" name="ldap_action_clear_group_mappings"><?php p($l->t('Clear Groupname-LDAP Group Mapping'));?></button></p> |
|
118 | + <p><strong><?php p($l->t('Internal Username')); ?></strong></p> |
|
119 | + <p class="ldapIndent"><?php p($l->t('By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users.')); ?></p> |
|
120 | + <p class="ldapIndent"><label for="ldap_expert_username_attr"><?php p($l->t('Internal Username Attribute:')); ?></label><input type="text" id="ldap_expert_username_attr" name="ldap_expert_username_attr" data-default="<?php p($_['ldap_expert_username_attr_default']); ?>" /></p> |
|
121 | + <p><strong><?php p($l->t('Override UUID detection')); ?></strong></p> |
|
122 | + <p class="ldapIndent"><?php p($l->t('By default, the UUID attribute is automatically detected. The UUID attribute is used to doubtlessly identify LDAP users and groups. Also, the internal username will be created based on the UUID, if not specified otherwise above. You can override the setting and pass an attribute of your choice. You must make sure that the attribute of your choice can be fetched for both users and groups and it is unique. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users and groups.')); ?></p> |
|
123 | + <p class="ldapIndent"><label for="ldap_expert_uuid_user_attr"><?php p($l->t('UUID Attribute for Users:')); ?></label><input type="text" id="ldap_expert_uuid_user_attr" name="ldap_expert_uuid_user_attr" data-default="<?php p($_['ldap_expert_uuid_user_attr_default']); ?>" /></p> |
|
124 | + <p class="ldapIndent"><label for="ldap_expert_uuid_group_attr"><?php p($l->t('UUID Attribute for Groups:')); ?></label><input type="text" id="ldap_expert_uuid_group_attr" name="ldap_expert_uuid_group_attr" data-default="<?php p($_['ldap_expert_uuid_group_attr_default']); ?>" /></p> |
|
125 | + <p><strong><?php p($l->t('Username-LDAP User Mapping')); ?></strong></p> |
|
126 | + <p class="ldapIndent"><?php p($l->t('Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have an internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage.')); ?></p> |
|
127 | + <p class="ldapIndent"><button type="button" id="ldap_action_clear_user_mappings" name="ldap_action_clear_user_mappings"><?php p($l->t('Clear Username-LDAP User Mapping')); ?></button><br/><button type="button" id="ldap_action_clear_group_mappings" name="ldap_action_clear_group_mappings"><?php p($l->t('Clear Groupname-LDAP Group Mapping')); ?></button></p> |
|
128 | 128 | <?php print_unescaped($_['settingControls']); ?> |
129 | 129 | </fieldset> |
130 | 130 | </div> |
@@ -97,7 +97,19 @@ |
||
97 | 97 | <p><label for="ldap_group_display_name"><?php p($l->t('Group Display Name Field'));?></label><input type="text" id="ldap_group_display_name" name="ldap_group_display_name" data-default="<?php p($_['ldap_group_display_name_default']); ?>" title="<?php p($l->t('The LDAP attribute to use to generate the groups\'s display name.'));?>" /></p> |
98 | 98 | <p><label for="ldap_base_groups"><?php p($l->t('Base Group Tree'));?></label><textarea id="ldap_base_groups" name="ldap_base_groups" placeholder="<?php p($l->t('One Group Base DN per line'));?>" data-default="<?php p($_['ldap_base_groups_default']); ?>" title="<?php p($l->t('Base Group Tree'));?>"></textarea></p> |
99 | 99 | <p><label for="ldap_attributes_for_group_search"><?php p($l->t('Group Search Attributes'));?></label><textarea id="ldap_attributes_for_group_search" name="ldap_attributes_for_group_search" placeholder="<?php p($l->t('Optional; one attribute per line'));?>" data-default="<?php p($_['ldap_attributes_for_group_search_default']); ?>" title="<?php p($l->t('Group Search Attributes'));?>"></textarea></p> |
100 | - <p><label for="ldap_group_member_assoc_attribute"><?php p($l->t('Group-Member association'));?></label><select id="ldap_group_member_assoc_attribute" name="ldap_group_member_assoc_attribute" data-default="<?php p($_['ldap_group_member_assoc_attribute_default']); ?>" ><option value="uniqueMember"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'uniqueMember')) p(' selected'); ?>>uniqueMember</option><option value="memberUid"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'memberUid')) p(' selected'); ?>>memberUid</option><option value="member"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'member')) p(' selected'); ?>>member (AD)</option><option value="gidNumber"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'gidNumber')) p(' selected'); ?>>gidNumber</option></select></p> <p><label for="ldap_dynamic_group_member_url"><?php p($l->t('Dynamic Group Member URL'));?></label><input type="text" id="ldap_dynamic_group_member_url" name="ldap_dynamic_group_member_url" title="<?php p($l->t('The LDAP attribute that on group objects contains an LDAP search URL that determines what objects belong to the group. (An empty setting disables dynamic group membership functionality.)'));?>" data-default="<?php p($_['ldap_dynamic_group_member_url_default']); ?>" /></p> |
|
100 | + <p><label for="ldap_group_member_assoc_attribute"><?php p($l->t('Group-Member association'));?></label><select id="ldap_group_member_assoc_attribute" name="ldap_group_member_assoc_attribute" data-default="<?php p($_['ldap_group_member_assoc_attribute_default']); ?>" ><option value="uniqueMember"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'uniqueMember')) { |
|
101 | + p(' selected'); |
|
102 | +} |
|
103 | +?>>uniqueMember</option><option value="memberUid"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'memberUid')) { |
|
104 | + p(' selected'); |
|
105 | +} |
|
106 | +?>>memberUid</option><option value="member"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'member')) { |
|
107 | + p(' selected'); |
|
108 | +} |
|
109 | +?>>member (AD)</option><option value="gidNumber"<?php if (isset($_['ldap_group_member_assoc_attribute']) && ($_['ldap_group_member_assoc_attribute'] === 'gidNumber')) { |
|
110 | + p(' selected'); |
|
111 | +} |
|
112 | +?>>gidNumber</option></select></p> <p><label for="ldap_dynamic_group_member_url"><?php p($l->t('Dynamic Group Member URL'));?></label><input type="text" id="ldap_dynamic_group_member_url" name="ldap_dynamic_group_member_url" title="<?php p($l->t('The LDAP attribute that on group objects contains an LDAP search URL that determines what objects belong to the group. (An empty setting disables dynamic group membership functionality.)'));?>" data-default="<?php p($_['ldap_dynamic_group_member_url_default']); ?>" /></p> |
|
101 | 113 | <p><label for="ldap_nested_groups"><?php p($l->t('Nested Groups'));?></label><input type="checkbox" id="ldap_nested_groups" name="ldap_nested_groups" value="1" data-default="<?php p($_['ldap_nested_groups_default']); ?>" title="<?php p($l->t('When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)'));?>" /></p> |
102 | 114 | <p><label for="ldap_paging_size"><?php p($l->t('Paging chunksize'));?></label><input type="number" id="ldap_paging_size" name="ldap_paging_size" title="<?php p($l->t('Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)'));?>" data-default="<?php p($_['ldap_paging_size_default']); ?>" /></p> |
103 | 115 | <p><label for="ldap_turn_on_pwd_change"><?php p($l->t('Enable LDAP password changes per user'));?></label><span class="inlinetable"><span class="tablerow left"><input type="checkbox" id="ldap_turn_on_pwd_change" name="ldap_turn_on_pwd_change" value="1" data-default="<?php p($_['ldap_turn_on_pwd_change_default']); ?>" title="<?php p($l->t('Allow LDAP users to change their password and allow Super Administrators and Group Administrators to change the password of their LDAP users. Only works when access control policies are configured accordingly on the LDAP server. As passwords are sent in plaintext to the LDAP server, transport encryption must be used and password hashing should be configured on the LDAP server.'));?>" /><span class="tablecell"><?php p($l->t('(New password is sent as plain text to LDAP)'));?></span></span> |
@@ -36,492 +36,492 @@ |
||
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 | - 'ldapDefaultPPolicyDN' => null, |
|
98 | - ); |
|
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 | + 'ldapDefaultPPolicyDN' => null, |
|
98 | + ); |
|
99 | 99 | |
100 | - /** |
|
101 | - * @param string $configPrefix |
|
102 | - * @param bool $autoRead |
|
103 | - */ |
|
104 | - public function __construct($configPrefix, $autoRead = true) { |
|
105 | - $this->configPrefix = $configPrefix; |
|
106 | - if($autoRead) { |
|
107 | - $this->readConfiguration(); |
|
108 | - } |
|
109 | - } |
|
100 | + /** |
|
101 | + * @param string $configPrefix |
|
102 | + * @param bool $autoRead |
|
103 | + */ |
|
104 | + public function __construct($configPrefix, $autoRead = true) { |
|
105 | + $this->configPrefix = $configPrefix; |
|
106 | + if($autoRead) { |
|
107 | + $this->readConfiguration(); |
|
108 | + } |
|
109 | + } |
|
110 | 110 | |
111 | - /** |
|
112 | - * @param string $name |
|
113 | - * @return mixed|null |
|
114 | - */ |
|
115 | - public function __get($name) { |
|
116 | - if(isset($this->config[$name])) { |
|
117 | - return $this->config[$name]; |
|
118 | - } |
|
119 | - return null; |
|
120 | - } |
|
111 | + /** |
|
112 | + * @param string $name |
|
113 | + * @return mixed|null |
|
114 | + */ |
|
115 | + public function __get($name) { |
|
116 | + if(isset($this->config[$name])) { |
|
117 | + return $this->config[$name]; |
|
118 | + } |
|
119 | + return null; |
|
120 | + } |
|
121 | 121 | |
122 | - /** |
|
123 | - * @param string $name |
|
124 | - * @param mixed $value |
|
125 | - */ |
|
126 | - public function __set($name, $value) { |
|
127 | - $this->setConfiguration(array($name => $value)); |
|
128 | - } |
|
122 | + /** |
|
123 | + * @param string $name |
|
124 | + * @param mixed $value |
|
125 | + */ |
|
126 | + public function __set($name, $value) { |
|
127 | + $this->setConfiguration(array($name => $value)); |
|
128 | + } |
|
129 | 129 | |
130 | - /** |
|
131 | - * @return array |
|
132 | - */ |
|
133 | - public function getConfiguration() { |
|
134 | - return $this->config; |
|
135 | - } |
|
130 | + /** |
|
131 | + * @return array |
|
132 | + */ |
|
133 | + public function getConfiguration() { |
|
134 | + return $this->config; |
|
135 | + } |
|
136 | 136 | |
137 | - /** |
|
138 | - * set LDAP configuration with values delivered by an array, not read |
|
139 | - * from configuration. It does not save the configuration! To do so, you |
|
140 | - * must call saveConfiguration afterwards. |
|
141 | - * @param array $config array that holds the config parameters in an associated |
|
142 | - * array |
|
143 | - * @param array &$applied optional; array where the set fields will be given to |
|
144 | - * @return false|null |
|
145 | - */ |
|
146 | - public function setConfiguration($config, &$applied = null) { |
|
147 | - if(!is_array($config)) { |
|
148 | - return false; |
|
149 | - } |
|
137 | + /** |
|
138 | + * set LDAP configuration with values delivered by an array, not read |
|
139 | + * from configuration. It does not save the configuration! To do so, you |
|
140 | + * must call saveConfiguration afterwards. |
|
141 | + * @param array $config array that holds the config parameters in an associated |
|
142 | + * array |
|
143 | + * @param array &$applied optional; array where the set fields will be given to |
|
144 | + * @return false|null |
|
145 | + */ |
|
146 | + public function setConfiguration($config, &$applied = null) { |
|
147 | + if(!is_array($config)) { |
|
148 | + return false; |
|
149 | + } |
|
150 | 150 | |
151 | - $cta = $this->getConfigTranslationArray(); |
|
152 | - foreach($config as $inputKey => $val) { |
|
153 | - if(strpos($inputKey, '_') !== false && array_key_exists($inputKey, $cta)) { |
|
154 | - $key = $cta[$inputKey]; |
|
155 | - } elseif(array_key_exists($inputKey, $this->config)) { |
|
156 | - $key = $inputKey; |
|
157 | - } else { |
|
158 | - continue; |
|
159 | - } |
|
151 | + $cta = $this->getConfigTranslationArray(); |
|
152 | + foreach($config as $inputKey => $val) { |
|
153 | + if(strpos($inputKey, '_') !== false && array_key_exists($inputKey, $cta)) { |
|
154 | + $key = $cta[$inputKey]; |
|
155 | + } elseif(array_key_exists($inputKey, $this->config)) { |
|
156 | + $key = $inputKey; |
|
157 | + } else { |
|
158 | + continue; |
|
159 | + } |
|
160 | 160 | |
161 | - $setMethod = 'setValue'; |
|
162 | - switch($key) { |
|
163 | - case 'ldapAgentPassword': |
|
164 | - $setMethod = 'setRawValue'; |
|
165 | - break; |
|
166 | - case 'homeFolderNamingRule': |
|
167 | - $trimmedVal = trim($val); |
|
168 | - if ($trimmedVal !== '' && strpos($val, 'attr:') === false) { |
|
169 | - $val = 'attr:'.$trimmedVal; |
|
170 | - } |
|
171 | - break; |
|
172 | - case 'ldapBase': |
|
173 | - case 'ldapBaseUsers': |
|
174 | - case 'ldapBaseGroups': |
|
175 | - case 'ldapAttributesForUserSearch': |
|
176 | - case 'ldapAttributesForGroupSearch': |
|
177 | - case 'ldapUserFilterObjectclass': |
|
178 | - case 'ldapUserFilterGroups': |
|
179 | - case 'ldapGroupFilterObjectclass': |
|
180 | - case 'ldapGroupFilterGroups': |
|
181 | - case 'ldapLoginFilterAttributes': |
|
182 | - $setMethod = 'setMultiLine'; |
|
183 | - break; |
|
184 | - } |
|
185 | - $this->$setMethod($key, $val); |
|
186 | - if(is_array($applied)) { |
|
187 | - $applied[] = $inputKey; |
|
188 | - } |
|
189 | - } |
|
190 | - return null; |
|
191 | - } |
|
161 | + $setMethod = 'setValue'; |
|
162 | + switch($key) { |
|
163 | + case 'ldapAgentPassword': |
|
164 | + $setMethod = 'setRawValue'; |
|
165 | + break; |
|
166 | + case 'homeFolderNamingRule': |
|
167 | + $trimmedVal = trim($val); |
|
168 | + if ($trimmedVal !== '' && strpos($val, 'attr:') === false) { |
|
169 | + $val = 'attr:'.$trimmedVal; |
|
170 | + } |
|
171 | + break; |
|
172 | + case 'ldapBase': |
|
173 | + case 'ldapBaseUsers': |
|
174 | + case 'ldapBaseGroups': |
|
175 | + case 'ldapAttributesForUserSearch': |
|
176 | + case 'ldapAttributesForGroupSearch': |
|
177 | + case 'ldapUserFilterObjectclass': |
|
178 | + case 'ldapUserFilterGroups': |
|
179 | + case 'ldapGroupFilterObjectclass': |
|
180 | + case 'ldapGroupFilterGroups': |
|
181 | + case 'ldapLoginFilterAttributes': |
|
182 | + $setMethod = 'setMultiLine'; |
|
183 | + break; |
|
184 | + } |
|
185 | + $this->$setMethod($key, $val); |
|
186 | + if(is_array($applied)) { |
|
187 | + $applied[] = $inputKey; |
|
188 | + } |
|
189 | + } |
|
190 | + return null; |
|
191 | + } |
|
192 | 192 | |
193 | - public function readConfiguration() { |
|
194 | - if(!$this->configRead && !is_null($this->configPrefix)) { |
|
195 | - $cta = array_flip($this->getConfigTranslationArray()); |
|
196 | - foreach($this->config as $key => $val) { |
|
197 | - if(!isset($cta[$key])) { |
|
198 | - //some are determined |
|
199 | - continue; |
|
200 | - } |
|
201 | - $dbKey = $cta[$key]; |
|
202 | - switch($key) { |
|
203 | - case 'ldapBase': |
|
204 | - case 'ldapBaseUsers': |
|
205 | - case 'ldapBaseGroups': |
|
206 | - case 'ldapAttributesForUserSearch': |
|
207 | - case 'ldapAttributesForGroupSearch': |
|
208 | - case 'ldapUserFilterObjectclass': |
|
209 | - case 'ldapUserFilterGroups': |
|
210 | - case 'ldapGroupFilterObjectclass': |
|
211 | - case 'ldapGroupFilterGroups': |
|
212 | - case 'ldapLoginFilterAttributes': |
|
213 | - $readMethod = 'getMultiLine'; |
|
214 | - break; |
|
215 | - case 'ldapIgnoreNamingRules': |
|
216 | - $readMethod = 'getSystemValue'; |
|
217 | - $dbKey = $key; |
|
218 | - break; |
|
219 | - case 'ldapAgentPassword': |
|
220 | - $readMethod = 'getPwd'; |
|
221 | - break; |
|
222 | - case 'ldapUserDisplayName2': |
|
223 | - case 'ldapGroupDisplayName': |
|
224 | - $readMethod = 'getLcValue'; |
|
225 | - break; |
|
226 | - case 'ldapUserDisplayName': |
|
227 | - default: |
|
228 | - // user display name does not lower case because |
|
229 | - // we rely on an upper case N as indicator whether to |
|
230 | - // auto-detect it or not. FIXME |
|
231 | - $readMethod = 'getValue'; |
|
232 | - break; |
|
233 | - } |
|
234 | - $this->config[$key] = $this->$readMethod($dbKey); |
|
235 | - } |
|
236 | - $this->configRead = true; |
|
237 | - } |
|
238 | - } |
|
193 | + public function readConfiguration() { |
|
194 | + if(!$this->configRead && !is_null($this->configPrefix)) { |
|
195 | + $cta = array_flip($this->getConfigTranslationArray()); |
|
196 | + foreach($this->config as $key => $val) { |
|
197 | + if(!isset($cta[$key])) { |
|
198 | + //some are determined |
|
199 | + continue; |
|
200 | + } |
|
201 | + $dbKey = $cta[$key]; |
|
202 | + switch($key) { |
|
203 | + case 'ldapBase': |
|
204 | + case 'ldapBaseUsers': |
|
205 | + case 'ldapBaseGroups': |
|
206 | + case 'ldapAttributesForUserSearch': |
|
207 | + case 'ldapAttributesForGroupSearch': |
|
208 | + case 'ldapUserFilterObjectclass': |
|
209 | + case 'ldapUserFilterGroups': |
|
210 | + case 'ldapGroupFilterObjectclass': |
|
211 | + case 'ldapGroupFilterGroups': |
|
212 | + case 'ldapLoginFilterAttributes': |
|
213 | + $readMethod = 'getMultiLine'; |
|
214 | + break; |
|
215 | + case 'ldapIgnoreNamingRules': |
|
216 | + $readMethod = 'getSystemValue'; |
|
217 | + $dbKey = $key; |
|
218 | + break; |
|
219 | + case 'ldapAgentPassword': |
|
220 | + $readMethod = 'getPwd'; |
|
221 | + break; |
|
222 | + case 'ldapUserDisplayName2': |
|
223 | + case 'ldapGroupDisplayName': |
|
224 | + $readMethod = 'getLcValue'; |
|
225 | + break; |
|
226 | + case 'ldapUserDisplayName': |
|
227 | + default: |
|
228 | + // user display name does not lower case because |
|
229 | + // we rely on an upper case N as indicator whether to |
|
230 | + // auto-detect it or not. FIXME |
|
231 | + $readMethod = 'getValue'; |
|
232 | + break; |
|
233 | + } |
|
234 | + $this->config[$key] = $this->$readMethod($dbKey); |
|
235 | + } |
|
236 | + $this->configRead = true; |
|
237 | + } |
|
238 | + } |
|
239 | 239 | |
240 | - /** |
|
241 | - * saves the current Configuration in the database |
|
242 | - */ |
|
243 | - public function saveConfiguration() { |
|
244 | - $cta = array_flip($this->getConfigTranslationArray()); |
|
245 | - foreach($this->config as $key => $value) { |
|
246 | - switch ($key) { |
|
247 | - case 'ldapAgentPassword': |
|
248 | - $value = base64_encode($value); |
|
249 | - break; |
|
250 | - case 'ldapBase': |
|
251 | - case 'ldapBaseUsers': |
|
252 | - case 'ldapBaseGroups': |
|
253 | - case 'ldapAttributesForUserSearch': |
|
254 | - case 'ldapAttributesForGroupSearch': |
|
255 | - case 'ldapUserFilterObjectclass': |
|
256 | - case 'ldapUserFilterGroups': |
|
257 | - case 'ldapGroupFilterObjectclass': |
|
258 | - case 'ldapGroupFilterGroups': |
|
259 | - case 'ldapLoginFilterAttributes': |
|
260 | - if(is_array($value)) { |
|
261 | - $value = implode("\n", $value); |
|
262 | - } |
|
263 | - break; |
|
264 | - //following options are not stored but detected, skip them |
|
265 | - case 'ldapIgnoreNamingRules': |
|
266 | - case 'hasPagedResultSupport': |
|
267 | - case 'ldapUuidUserAttribute': |
|
268 | - case 'ldapUuidGroupAttribute': |
|
269 | - continue 2; |
|
270 | - } |
|
271 | - if(is_null($value)) { |
|
272 | - $value = ''; |
|
273 | - } |
|
274 | - $this->saveValue($cta[$key], $value); |
|
275 | - } |
|
276 | - } |
|
240 | + /** |
|
241 | + * saves the current Configuration in the database |
|
242 | + */ |
|
243 | + public function saveConfiguration() { |
|
244 | + $cta = array_flip($this->getConfigTranslationArray()); |
|
245 | + foreach($this->config as $key => $value) { |
|
246 | + switch ($key) { |
|
247 | + case 'ldapAgentPassword': |
|
248 | + $value = base64_encode($value); |
|
249 | + break; |
|
250 | + case 'ldapBase': |
|
251 | + case 'ldapBaseUsers': |
|
252 | + case 'ldapBaseGroups': |
|
253 | + case 'ldapAttributesForUserSearch': |
|
254 | + case 'ldapAttributesForGroupSearch': |
|
255 | + case 'ldapUserFilterObjectclass': |
|
256 | + case 'ldapUserFilterGroups': |
|
257 | + case 'ldapGroupFilterObjectclass': |
|
258 | + case 'ldapGroupFilterGroups': |
|
259 | + case 'ldapLoginFilterAttributes': |
|
260 | + if(is_array($value)) { |
|
261 | + $value = implode("\n", $value); |
|
262 | + } |
|
263 | + break; |
|
264 | + //following options are not stored but detected, skip them |
|
265 | + case 'ldapIgnoreNamingRules': |
|
266 | + case 'hasPagedResultSupport': |
|
267 | + case 'ldapUuidUserAttribute': |
|
268 | + case 'ldapUuidGroupAttribute': |
|
269 | + continue 2; |
|
270 | + } |
|
271 | + if(is_null($value)) { |
|
272 | + $value = ''; |
|
273 | + } |
|
274 | + $this->saveValue($cta[$key], $value); |
|
275 | + } |
|
276 | + } |
|
277 | 277 | |
278 | - /** |
|
279 | - * @param string $varName |
|
280 | - * @return array|string |
|
281 | - */ |
|
282 | - protected function getMultiLine($varName) { |
|
283 | - $value = $this->getValue($varName); |
|
284 | - if(empty($value)) { |
|
285 | - $value = ''; |
|
286 | - } else { |
|
287 | - $value = preg_split('/\r\n|\r|\n/', $value); |
|
288 | - } |
|
278 | + /** |
|
279 | + * @param string $varName |
|
280 | + * @return array|string |
|
281 | + */ |
|
282 | + protected function getMultiLine($varName) { |
|
283 | + $value = $this->getValue($varName); |
|
284 | + if(empty($value)) { |
|
285 | + $value = ''; |
|
286 | + } else { |
|
287 | + $value = preg_split('/\r\n|\r|\n/', $value); |
|
288 | + } |
|
289 | 289 | |
290 | - return $value; |
|
291 | - } |
|
290 | + return $value; |
|
291 | + } |
|
292 | 292 | |
293 | - /** |
|
294 | - * Sets multi-line values as arrays |
|
295 | - * |
|
296 | - * @param string $varName name of config-key |
|
297 | - * @param array|string $value to set |
|
298 | - */ |
|
299 | - protected function setMultiLine($varName, $value) { |
|
300 | - if(empty($value)) { |
|
301 | - $value = ''; |
|
302 | - } else if (!is_array($value)) { |
|
303 | - $value = preg_split('/\r\n|\r|\n|;/', $value); |
|
304 | - if($value === false) { |
|
305 | - $value = ''; |
|
306 | - } |
|
307 | - } |
|
293 | + /** |
|
294 | + * Sets multi-line values as arrays |
|
295 | + * |
|
296 | + * @param string $varName name of config-key |
|
297 | + * @param array|string $value to set |
|
298 | + */ |
|
299 | + protected function setMultiLine($varName, $value) { |
|
300 | + if(empty($value)) { |
|
301 | + $value = ''; |
|
302 | + } else if (!is_array($value)) { |
|
303 | + $value = preg_split('/\r\n|\r|\n|;/', $value); |
|
304 | + if($value === false) { |
|
305 | + $value = ''; |
|
306 | + } |
|
307 | + } |
|
308 | 308 | |
309 | - if(!is_array($value)) { |
|
310 | - $finalValue = trim($value); |
|
311 | - } else { |
|
312 | - $finalValue = []; |
|
313 | - foreach($value as $key => $val) { |
|
314 | - if(is_string($val)) { |
|
315 | - $val = trim($val); |
|
316 | - if ($val !== '') { |
|
317 | - //accidental line breaks are not wanted and can cause |
|
318 | - // odd behaviour. Thus, away with them. |
|
319 | - $finalValue[] = $val; |
|
320 | - } |
|
321 | - } else { |
|
322 | - $finalValue[] = $val; |
|
323 | - } |
|
324 | - } |
|
325 | - } |
|
309 | + if(!is_array($value)) { |
|
310 | + $finalValue = trim($value); |
|
311 | + } else { |
|
312 | + $finalValue = []; |
|
313 | + foreach($value as $key => $val) { |
|
314 | + if(is_string($val)) { |
|
315 | + $val = trim($val); |
|
316 | + if ($val !== '') { |
|
317 | + //accidental line breaks are not wanted and can cause |
|
318 | + // odd behaviour. Thus, away with them. |
|
319 | + $finalValue[] = $val; |
|
320 | + } |
|
321 | + } else { |
|
322 | + $finalValue[] = $val; |
|
323 | + } |
|
324 | + } |
|
325 | + } |
|
326 | 326 | |
327 | - $this->setRawValue($varName, $finalValue); |
|
328 | - } |
|
327 | + $this->setRawValue($varName, $finalValue); |
|
328 | + } |
|
329 | 329 | |
330 | - /** |
|
331 | - * @param string $varName |
|
332 | - * @return string |
|
333 | - */ |
|
334 | - protected function getPwd($varName) { |
|
335 | - return base64_decode($this->getValue($varName)); |
|
336 | - } |
|
330 | + /** |
|
331 | + * @param string $varName |
|
332 | + * @return string |
|
333 | + */ |
|
334 | + protected function getPwd($varName) { |
|
335 | + return base64_decode($this->getValue($varName)); |
|
336 | + } |
|
337 | 337 | |
338 | - /** |
|
339 | - * @param string $varName |
|
340 | - * @return string |
|
341 | - */ |
|
342 | - protected function getLcValue($varName) { |
|
343 | - return mb_strtolower($this->getValue($varName), 'UTF-8'); |
|
344 | - } |
|
338 | + /** |
|
339 | + * @param string $varName |
|
340 | + * @return string |
|
341 | + */ |
|
342 | + protected function getLcValue($varName) { |
|
343 | + return mb_strtolower($this->getValue($varName), 'UTF-8'); |
|
344 | + } |
|
345 | 345 | |
346 | - /** |
|
347 | - * @param string $varName |
|
348 | - * @return string |
|
349 | - */ |
|
350 | - protected function getSystemValue($varName) { |
|
351 | - //FIXME: if another system value is added, softcode the default value |
|
352 | - return \OCP\Config::getSystemValue($varName, false); |
|
353 | - } |
|
346 | + /** |
|
347 | + * @param string $varName |
|
348 | + * @return string |
|
349 | + */ |
|
350 | + protected function getSystemValue($varName) { |
|
351 | + //FIXME: if another system value is added, softcode the default value |
|
352 | + return \OCP\Config::getSystemValue($varName, false); |
|
353 | + } |
|
354 | 354 | |
355 | - /** |
|
356 | - * @param string $varName |
|
357 | - * @return string |
|
358 | - */ |
|
359 | - protected function getValue($varName) { |
|
360 | - static $defaults; |
|
361 | - if(is_null($defaults)) { |
|
362 | - $defaults = $this->getDefaults(); |
|
363 | - } |
|
364 | - return \OCP\Config::getAppValue('user_ldap', |
|
365 | - $this->configPrefix.$varName, |
|
366 | - $defaults[$varName]); |
|
367 | - } |
|
355 | + /** |
|
356 | + * @param string $varName |
|
357 | + * @return string |
|
358 | + */ |
|
359 | + protected function getValue($varName) { |
|
360 | + static $defaults; |
|
361 | + if(is_null($defaults)) { |
|
362 | + $defaults = $this->getDefaults(); |
|
363 | + } |
|
364 | + return \OCP\Config::getAppValue('user_ldap', |
|
365 | + $this->configPrefix.$varName, |
|
366 | + $defaults[$varName]); |
|
367 | + } |
|
368 | 368 | |
369 | - /** |
|
370 | - * Sets a scalar value. |
|
371 | - * |
|
372 | - * @param string $varName name of config key |
|
373 | - * @param mixed $value to set |
|
374 | - */ |
|
375 | - protected function setValue($varName, $value) { |
|
376 | - if(is_string($value)) { |
|
377 | - $value = trim($value); |
|
378 | - } |
|
379 | - $this->config[$varName] = $value; |
|
380 | - } |
|
369 | + /** |
|
370 | + * Sets a scalar value. |
|
371 | + * |
|
372 | + * @param string $varName name of config key |
|
373 | + * @param mixed $value to set |
|
374 | + */ |
|
375 | + protected function setValue($varName, $value) { |
|
376 | + if(is_string($value)) { |
|
377 | + $value = trim($value); |
|
378 | + } |
|
379 | + $this->config[$varName] = $value; |
|
380 | + } |
|
381 | 381 | |
382 | - /** |
|
383 | - * Sets a scalar value without trimming. |
|
384 | - * |
|
385 | - * @param string $varName name of config key |
|
386 | - * @param mixed $value to set |
|
387 | - */ |
|
388 | - protected function setRawValue($varName, $value) { |
|
389 | - $this->config[$varName] = $value; |
|
390 | - } |
|
382 | + /** |
|
383 | + * Sets a scalar value without trimming. |
|
384 | + * |
|
385 | + * @param string $varName name of config key |
|
386 | + * @param mixed $value to set |
|
387 | + */ |
|
388 | + protected function setRawValue($varName, $value) { |
|
389 | + $this->config[$varName] = $value; |
|
390 | + } |
|
391 | 391 | |
392 | - /** |
|
393 | - * @param string $varName |
|
394 | - * @param string $value |
|
395 | - * @return bool |
|
396 | - */ |
|
397 | - protected function saveValue($varName, $value) { |
|
398 | - \OC::$server->getConfig()->setAppValue( |
|
399 | - 'user_ldap', |
|
400 | - $this->configPrefix.$varName, |
|
401 | - $value |
|
402 | - ); |
|
403 | - return true; |
|
404 | - } |
|
392 | + /** |
|
393 | + * @param string $varName |
|
394 | + * @param string $value |
|
395 | + * @return bool |
|
396 | + */ |
|
397 | + protected function saveValue($varName, $value) { |
|
398 | + \OC::$server->getConfig()->setAppValue( |
|
399 | + 'user_ldap', |
|
400 | + $this->configPrefix.$varName, |
|
401 | + $value |
|
402 | + ); |
|
403 | + return true; |
|
404 | + } |
|
405 | 405 | |
406 | - /** |
|
407 | - * @return array an associative array with the default values. Keys are correspond |
|
408 | - * to config-value entries in the database table |
|
409 | - */ |
|
410 | - public function getDefaults() { |
|
411 | - return array( |
|
412 | - 'ldap_host' => '', |
|
413 | - 'ldap_port' => '', |
|
414 | - 'ldap_backup_host' => '', |
|
415 | - 'ldap_backup_port' => '', |
|
416 | - 'ldap_override_main_server' => '', |
|
417 | - 'ldap_dn' => '', |
|
418 | - 'ldap_agent_password' => '', |
|
419 | - 'ldap_base' => '', |
|
420 | - 'ldap_base_users' => '', |
|
421 | - 'ldap_base_groups' => '', |
|
422 | - 'ldap_userlist_filter' => '', |
|
423 | - 'ldap_user_filter_mode' => 0, |
|
424 | - 'ldap_userfilter_objectclass' => '', |
|
425 | - 'ldap_userfilter_groups' => '', |
|
426 | - 'ldap_login_filter' => '', |
|
427 | - 'ldap_login_filter_mode' => 0, |
|
428 | - 'ldap_loginfilter_email' => 0, |
|
429 | - 'ldap_loginfilter_username' => 1, |
|
430 | - 'ldap_loginfilter_attributes' => '', |
|
431 | - 'ldap_group_filter' => '', |
|
432 | - 'ldap_group_filter_mode' => 0, |
|
433 | - 'ldap_groupfilter_objectclass' => '', |
|
434 | - 'ldap_groupfilter_groups' => '', |
|
435 | - 'ldap_gid_number' => 'gidNumber', |
|
436 | - 'ldap_display_name' => 'displayName', |
|
437 | - 'ldap_user_display_name_2' => '', |
|
438 | - 'ldap_group_display_name' => 'cn', |
|
439 | - 'ldap_tls' => 0, |
|
440 | - 'ldap_quota_def' => '', |
|
441 | - 'ldap_quota_attr' => '', |
|
442 | - 'ldap_email_attr' => '', |
|
443 | - 'ldap_group_member_assoc_attribute' => 'uniqueMember', |
|
444 | - 'ldap_cache_ttl' => 600, |
|
445 | - 'ldap_uuid_user_attribute' => 'auto', |
|
446 | - 'ldap_uuid_group_attribute' => 'auto', |
|
447 | - 'home_folder_naming_rule' => '', |
|
448 | - 'ldap_turn_off_cert_check' => 0, |
|
449 | - 'ldap_configuration_active' => 0, |
|
450 | - 'ldap_attributes_for_user_search' => '', |
|
451 | - 'ldap_attributes_for_group_search' => '', |
|
452 | - 'ldap_expert_username_attr' => '', |
|
453 | - 'ldap_expert_uuid_user_attr' => '', |
|
454 | - 'ldap_expert_uuid_group_attr' => '', |
|
455 | - 'has_memberof_filter_support' => 0, |
|
456 | - 'use_memberof_to_detect_membership' => 1, |
|
457 | - 'last_jpegPhoto_lookup' => 0, |
|
458 | - 'ldap_nested_groups' => 0, |
|
459 | - 'ldap_paging_size' => 500, |
|
460 | - 'ldap_turn_on_pwd_change' => 0, |
|
461 | - 'ldap_experienced_admin' => 0, |
|
462 | - 'ldap_dynamic_group_member_url' => '', |
|
463 | - 'ldap_default_ppolicy_dn' => '', |
|
464 | - ); |
|
465 | - } |
|
406 | + /** |
|
407 | + * @return array an associative array with the default values. Keys are correspond |
|
408 | + * to config-value entries in the database table |
|
409 | + */ |
|
410 | + public function getDefaults() { |
|
411 | + return array( |
|
412 | + 'ldap_host' => '', |
|
413 | + 'ldap_port' => '', |
|
414 | + 'ldap_backup_host' => '', |
|
415 | + 'ldap_backup_port' => '', |
|
416 | + 'ldap_override_main_server' => '', |
|
417 | + 'ldap_dn' => '', |
|
418 | + 'ldap_agent_password' => '', |
|
419 | + 'ldap_base' => '', |
|
420 | + 'ldap_base_users' => '', |
|
421 | + 'ldap_base_groups' => '', |
|
422 | + 'ldap_userlist_filter' => '', |
|
423 | + 'ldap_user_filter_mode' => 0, |
|
424 | + 'ldap_userfilter_objectclass' => '', |
|
425 | + 'ldap_userfilter_groups' => '', |
|
426 | + 'ldap_login_filter' => '', |
|
427 | + 'ldap_login_filter_mode' => 0, |
|
428 | + 'ldap_loginfilter_email' => 0, |
|
429 | + 'ldap_loginfilter_username' => 1, |
|
430 | + 'ldap_loginfilter_attributes' => '', |
|
431 | + 'ldap_group_filter' => '', |
|
432 | + 'ldap_group_filter_mode' => 0, |
|
433 | + 'ldap_groupfilter_objectclass' => '', |
|
434 | + 'ldap_groupfilter_groups' => '', |
|
435 | + 'ldap_gid_number' => 'gidNumber', |
|
436 | + 'ldap_display_name' => 'displayName', |
|
437 | + 'ldap_user_display_name_2' => '', |
|
438 | + 'ldap_group_display_name' => 'cn', |
|
439 | + 'ldap_tls' => 0, |
|
440 | + 'ldap_quota_def' => '', |
|
441 | + 'ldap_quota_attr' => '', |
|
442 | + 'ldap_email_attr' => '', |
|
443 | + 'ldap_group_member_assoc_attribute' => 'uniqueMember', |
|
444 | + 'ldap_cache_ttl' => 600, |
|
445 | + 'ldap_uuid_user_attribute' => 'auto', |
|
446 | + 'ldap_uuid_group_attribute' => 'auto', |
|
447 | + 'home_folder_naming_rule' => '', |
|
448 | + 'ldap_turn_off_cert_check' => 0, |
|
449 | + 'ldap_configuration_active' => 0, |
|
450 | + 'ldap_attributes_for_user_search' => '', |
|
451 | + 'ldap_attributes_for_group_search' => '', |
|
452 | + 'ldap_expert_username_attr' => '', |
|
453 | + 'ldap_expert_uuid_user_attr' => '', |
|
454 | + 'ldap_expert_uuid_group_attr' => '', |
|
455 | + 'has_memberof_filter_support' => 0, |
|
456 | + 'use_memberof_to_detect_membership' => 1, |
|
457 | + 'last_jpegPhoto_lookup' => 0, |
|
458 | + 'ldap_nested_groups' => 0, |
|
459 | + 'ldap_paging_size' => 500, |
|
460 | + 'ldap_turn_on_pwd_change' => 0, |
|
461 | + 'ldap_experienced_admin' => 0, |
|
462 | + 'ldap_dynamic_group_member_url' => '', |
|
463 | + 'ldap_default_ppolicy_dn' => '', |
|
464 | + ); |
|
465 | + } |
|
466 | 466 | |
467 | - /** |
|
468 | - * @return array that maps internal variable names to database fields |
|
469 | - */ |
|
470 | - public function getConfigTranslationArray() { |
|
471 | - //TODO: merge them into one representation |
|
472 | - static $array = array( |
|
473 | - 'ldap_host' => 'ldapHost', |
|
474 | - 'ldap_port' => 'ldapPort', |
|
475 | - 'ldap_backup_host' => 'ldapBackupHost', |
|
476 | - 'ldap_backup_port' => 'ldapBackupPort', |
|
477 | - 'ldap_override_main_server' => 'ldapOverrideMainServer', |
|
478 | - 'ldap_dn' => 'ldapAgentName', |
|
479 | - 'ldap_agent_password' => 'ldapAgentPassword', |
|
480 | - 'ldap_base' => 'ldapBase', |
|
481 | - 'ldap_base_users' => 'ldapBaseUsers', |
|
482 | - 'ldap_base_groups' => 'ldapBaseGroups', |
|
483 | - 'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass', |
|
484 | - 'ldap_userfilter_groups' => 'ldapUserFilterGroups', |
|
485 | - 'ldap_userlist_filter' => 'ldapUserFilter', |
|
486 | - 'ldap_user_filter_mode' => 'ldapUserFilterMode', |
|
487 | - 'ldap_login_filter' => 'ldapLoginFilter', |
|
488 | - 'ldap_login_filter_mode' => 'ldapLoginFilterMode', |
|
489 | - 'ldap_loginfilter_email' => 'ldapLoginFilterEmail', |
|
490 | - 'ldap_loginfilter_username' => 'ldapLoginFilterUsername', |
|
491 | - 'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes', |
|
492 | - 'ldap_group_filter' => 'ldapGroupFilter', |
|
493 | - 'ldap_group_filter_mode' => 'ldapGroupFilterMode', |
|
494 | - 'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass', |
|
495 | - 'ldap_groupfilter_groups' => 'ldapGroupFilterGroups', |
|
496 | - 'ldap_gid_number' => 'ldapGidNumber', |
|
497 | - 'ldap_display_name' => 'ldapUserDisplayName', |
|
498 | - 'ldap_user_display_name_2' => 'ldapUserDisplayName2', |
|
499 | - 'ldap_group_display_name' => 'ldapGroupDisplayName', |
|
500 | - 'ldap_tls' => 'ldapTLS', |
|
501 | - 'ldap_quota_def' => 'ldapQuotaDefault', |
|
502 | - 'ldap_quota_attr' => 'ldapQuotaAttribute', |
|
503 | - 'ldap_email_attr' => 'ldapEmailAttribute', |
|
504 | - 'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr', |
|
505 | - 'ldap_cache_ttl' => 'ldapCacheTTL', |
|
506 | - 'home_folder_naming_rule' => 'homeFolderNamingRule', |
|
507 | - 'ldap_turn_off_cert_check' => 'turnOffCertCheck', |
|
508 | - 'ldap_configuration_active' => 'ldapConfigurationActive', |
|
509 | - 'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch', |
|
510 | - 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch', |
|
511 | - 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr', |
|
512 | - 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr', |
|
513 | - 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr', |
|
514 | - 'has_memberof_filter_support' => 'hasMemberOfFilterSupport', |
|
515 | - 'use_memberof_to_detect_membership' => 'useMemberOfToDetectMembership', |
|
516 | - 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup', |
|
517 | - 'ldap_nested_groups' => 'ldapNestedGroups', |
|
518 | - 'ldap_paging_size' => 'ldapPagingSize', |
|
519 | - 'ldap_turn_on_pwd_change' => 'turnOnPasswordChange', |
|
520 | - 'ldap_experienced_admin' => 'ldapExperiencedAdmin', |
|
521 | - 'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL', |
|
522 | - 'ldap_default_ppolicy_dn' => 'ldapDefaultPPolicyDN', |
|
523 | - ); |
|
524 | - return $array; |
|
525 | - } |
|
467 | + /** |
|
468 | + * @return array that maps internal variable names to database fields |
|
469 | + */ |
|
470 | + public function getConfigTranslationArray() { |
|
471 | + //TODO: merge them into one representation |
|
472 | + static $array = array( |
|
473 | + 'ldap_host' => 'ldapHost', |
|
474 | + 'ldap_port' => 'ldapPort', |
|
475 | + 'ldap_backup_host' => 'ldapBackupHost', |
|
476 | + 'ldap_backup_port' => 'ldapBackupPort', |
|
477 | + 'ldap_override_main_server' => 'ldapOverrideMainServer', |
|
478 | + 'ldap_dn' => 'ldapAgentName', |
|
479 | + 'ldap_agent_password' => 'ldapAgentPassword', |
|
480 | + 'ldap_base' => 'ldapBase', |
|
481 | + 'ldap_base_users' => 'ldapBaseUsers', |
|
482 | + 'ldap_base_groups' => 'ldapBaseGroups', |
|
483 | + 'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass', |
|
484 | + 'ldap_userfilter_groups' => 'ldapUserFilterGroups', |
|
485 | + 'ldap_userlist_filter' => 'ldapUserFilter', |
|
486 | + 'ldap_user_filter_mode' => 'ldapUserFilterMode', |
|
487 | + 'ldap_login_filter' => 'ldapLoginFilter', |
|
488 | + 'ldap_login_filter_mode' => 'ldapLoginFilterMode', |
|
489 | + 'ldap_loginfilter_email' => 'ldapLoginFilterEmail', |
|
490 | + 'ldap_loginfilter_username' => 'ldapLoginFilterUsername', |
|
491 | + 'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes', |
|
492 | + 'ldap_group_filter' => 'ldapGroupFilter', |
|
493 | + 'ldap_group_filter_mode' => 'ldapGroupFilterMode', |
|
494 | + 'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass', |
|
495 | + 'ldap_groupfilter_groups' => 'ldapGroupFilterGroups', |
|
496 | + 'ldap_gid_number' => 'ldapGidNumber', |
|
497 | + 'ldap_display_name' => 'ldapUserDisplayName', |
|
498 | + 'ldap_user_display_name_2' => 'ldapUserDisplayName2', |
|
499 | + 'ldap_group_display_name' => 'ldapGroupDisplayName', |
|
500 | + 'ldap_tls' => 'ldapTLS', |
|
501 | + 'ldap_quota_def' => 'ldapQuotaDefault', |
|
502 | + 'ldap_quota_attr' => 'ldapQuotaAttribute', |
|
503 | + 'ldap_email_attr' => 'ldapEmailAttribute', |
|
504 | + 'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr', |
|
505 | + 'ldap_cache_ttl' => 'ldapCacheTTL', |
|
506 | + 'home_folder_naming_rule' => 'homeFolderNamingRule', |
|
507 | + 'ldap_turn_off_cert_check' => 'turnOffCertCheck', |
|
508 | + 'ldap_configuration_active' => 'ldapConfigurationActive', |
|
509 | + 'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch', |
|
510 | + 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch', |
|
511 | + 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr', |
|
512 | + 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr', |
|
513 | + 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr', |
|
514 | + 'has_memberof_filter_support' => 'hasMemberOfFilterSupport', |
|
515 | + 'use_memberof_to_detect_membership' => 'useMemberOfToDetectMembership', |
|
516 | + 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup', |
|
517 | + 'ldap_nested_groups' => 'ldapNestedGroups', |
|
518 | + 'ldap_paging_size' => 'ldapPagingSize', |
|
519 | + 'ldap_turn_on_pwd_change' => 'turnOnPasswordChange', |
|
520 | + 'ldap_experienced_admin' => 'ldapExperiencedAdmin', |
|
521 | + 'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL', |
|
522 | + 'ldap_default_ppolicy_dn' => 'ldapDefaultPPolicyDN', |
|
523 | + ); |
|
524 | + return $array; |
|
525 | + } |
|
526 | 526 | |
527 | 527 | } |
@@ -41,1055 +41,1055 @@ |
||
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' . $gid; |
|
278 | - $groupName = $this->access->connection->getFromCache($cacheKey); |
|
279 | - if(!is_null($groupName) && isset($groupName)) { |
|
280 | - return $groupName; |
|
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 Nextcloud 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 Nextcloud 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->nextcloudUserNames($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 | - // memberof doesn't support memberuid, so skip it here. |
|
662 | - if(intval($this->access->connection->hasMemberOfFilterSupport) === 1 |
|
663 | - && intval($this->access->connection->useMemberOfToDetectMembership) === 1 |
|
664 | - && strtolower($this->access->connection->ldapGroupMemberAssocAttr) !== 'memberuid' |
|
665 | - ) { |
|
666 | - $groupDNs = $this->_getGroupDNsFromMemberOf($userDN); |
|
667 | - if (is_array($groupDNs)) { |
|
668 | - foreach ($groupDNs as $dn) { |
|
669 | - $groupName = $this->access->dn2groupname($dn); |
|
670 | - if(is_string($groupName)) { |
|
671 | - // be sure to never return false if the dn could not be |
|
672 | - // resolved to a name, for whatever reason. |
|
673 | - $groups[] = $groupName; |
|
674 | - } |
|
675 | - } |
|
676 | - } |
|
677 | - |
|
678 | - if($primaryGroup !== false) { |
|
679 | - $groups[] = $primaryGroup; |
|
680 | - } |
|
681 | - if($gidGroupName !== false) { |
|
682 | - $groups[] = $gidGroupName; |
|
683 | - } |
|
684 | - $this->access->connection->writeToCache($cacheKey, $groups); |
|
685 | - return $groups; |
|
686 | - } |
|
687 | - |
|
688 | - //uniqueMember takes DN, memberuid the uid, so we need to distinguish |
|
689 | - if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember') |
|
690 | - || (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member') |
|
691 | - ) { |
|
692 | - $uid = $userDN; |
|
693 | - } else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') { |
|
694 | - $result = $this->access->readAttribute($userDN, 'uid'); |
|
695 | - if ($result === false) { |
|
696 | - \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '. |
|
697 | - $this->access->connection->ldapHost, \OCP\Util::DEBUG); |
|
698 | - } |
|
699 | - $uid = $result[0]; |
|
700 | - } else { |
|
701 | - // just in case |
|
702 | - $uid = $userDN; |
|
703 | - } |
|
704 | - |
|
705 | - if(isset($this->cachedGroupsByMember[$uid])) { |
|
706 | - $groups = array_merge($groups, $this->cachedGroupsByMember[$uid]); |
|
707 | - } else { |
|
708 | - $groupsByMember = array_values($this->getGroupsByMember($uid)); |
|
709 | - $groupsByMember = $this->access->nextcloudGroupNames($groupsByMember); |
|
710 | - $this->cachedGroupsByMember[$uid] = $groupsByMember; |
|
711 | - $groups = array_merge($groups, $groupsByMember); |
|
712 | - } |
|
713 | - |
|
714 | - if($primaryGroup !== false) { |
|
715 | - $groups[] = $primaryGroup; |
|
716 | - } |
|
717 | - if($gidGroupName !== false) { |
|
718 | - $groups[] = $gidGroupName; |
|
719 | - } |
|
720 | - |
|
721 | - $groups = array_unique($groups, SORT_LOCALE_STRING); |
|
722 | - $this->access->connection->writeToCache($cacheKey, $groups); |
|
723 | - |
|
724 | - return $groups; |
|
725 | - } |
|
726 | - |
|
727 | - /** |
|
728 | - * @param string $dn |
|
729 | - * @param array|null &$seen |
|
730 | - * @return array |
|
731 | - */ |
|
732 | - private function getGroupsByMember($dn, &$seen = null) { |
|
733 | - if ($seen === null) { |
|
734 | - $seen = array(); |
|
735 | - } |
|
736 | - $allGroups = array(); |
|
737 | - if (array_key_exists($dn, $seen)) { |
|
738 | - // avoid loops |
|
739 | - return array(); |
|
740 | - } |
|
741 | - $seen[$dn] = true; |
|
742 | - $filter = $this->access->combineFilterWithAnd(array( |
|
743 | - $this->access->connection->ldapGroupFilter, |
|
744 | - $this->access->connection->ldapGroupMemberAssocAttr.'='.$dn |
|
745 | - )); |
|
746 | - $groups = $this->access->fetchListOfGroups($filter, |
|
747 | - array($this->access->connection->ldapGroupDisplayName, 'dn')); |
|
748 | - if (is_array($groups)) { |
|
749 | - foreach ($groups as $groupobj) { |
|
750 | - $groupDN = $groupobj['dn'][0]; |
|
751 | - $allGroups[$groupDN] = $groupobj; |
|
752 | - $nestedGroups = $this->access->connection->ldapNestedGroups; |
|
753 | - if (!empty($nestedGroups)) { |
|
754 | - $supergroups = $this->getGroupsByMember($groupDN, $seen); |
|
755 | - if (is_array($supergroups) && (count($supergroups)>0)) { |
|
756 | - $allGroups = array_merge($allGroups, $supergroups); |
|
757 | - } |
|
758 | - } |
|
759 | - } |
|
760 | - } |
|
761 | - return $allGroups; |
|
762 | - } |
|
763 | - |
|
764 | - /** |
|
765 | - * get a list of all users in a group |
|
766 | - * |
|
767 | - * @param string $gid |
|
768 | - * @param string $search |
|
769 | - * @param int $limit |
|
770 | - * @param int $offset |
|
771 | - * @return array with user ids |
|
772 | - */ |
|
773 | - public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { |
|
774 | - if(!$this->enabled) { |
|
775 | - return array(); |
|
776 | - } |
|
777 | - if(!$this->groupExists($gid)) { |
|
778 | - return array(); |
|
779 | - } |
|
780 | - $search = $this->access->escapeFilterPart($search, true); |
|
781 | - $cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset; |
|
782 | - // check for cache of the exact query |
|
783 | - $groupUsers = $this->access->connection->getFromCache($cacheKey); |
|
784 | - if(!is_null($groupUsers)) { |
|
785 | - return $groupUsers; |
|
786 | - } |
|
787 | - |
|
788 | - // check for cache of the query without limit and offset |
|
789 | - $groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search); |
|
790 | - if(!is_null($groupUsers)) { |
|
791 | - $groupUsers = array_slice($groupUsers, $offset, $limit); |
|
792 | - $this->access->connection->writeToCache($cacheKey, $groupUsers); |
|
793 | - return $groupUsers; |
|
794 | - } |
|
795 | - |
|
796 | - if($limit === -1) { |
|
797 | - $limit = null; |
|
798 | - } |
|
799 | - $groupDN = $this->access->groupname2dn($gid); |
|
800 | - if(!$groupDN) { |
|
801 | - // group couldn't be found, return empty resultset |
|
802 | - $this->access->connection->writeToCache($cacheKey, array()); |
|
803 | - return array(); |
|
804 | - } |
|
805 | - |
|
806 | - $primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset); |
|
807 | - $members = array_keys($this->_groupMembers($groupDN)); |
|
808 | - if(!$members && empty($primaryUsers)) { |
|
809 | - //in case users could not be retrieved, return empty result set |
|
810 | - $this->access->connection->writeToCache($cacheKey, array()); |
|
811 | - return array(); |
|
812 | - } |
|
813 | - |
|
814 | - $posixGroupUsers = $this->getUsersInGidNumber($groupDN, $search, $limit, $offset); |
|
815 | - $members = array_keys($this->_groupMembers($groupDN)); |
|
816 | - if(!$members && empty($posixGroupUsers)) { |
|
817 | - //in case users could not be retrieved, return empty result set |
|
818 | - $this->access->connection->writeToCache($cacheKey, []); |
|
819 | - return []; |
|
820 | - } |
|
821 | - |
|
822 | - $groupUsers = array(); |
|
823 | - $isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid'); |
|
824 | - $attrs = $this->access->userManager->getAttributes(true); |
|
825 | - foreach($members as $member) { |
|
826 | - if($isMemberUid) { |
|
827 | - //we got uids, need to get their DNs to 'translate' them to user names |
|
828 | - $filter = $this->access->combineFilterWithAnd(array( |
|
829 | - str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), |
|
830 | - $this->access->getFilterPartForUserSearch($search) |
|
831 | - )); |
|
832 | - $ldap_users = $this->access->fetchListOfUsers($filter, $attrs, 1); |
|
833 | - if(count($ldap_users) < 1) { |
|
834 | - continue; |
|
835 | - } |
|
836 | - $groupUsers[] = $this->access->dn2username($ldap_users[0]['dn'][0]); |
|
837 | - } else { |
|
838 | - //we got DNs, check if we need to filter by search or we can give back all of them |
|
839 | - if ($search !== '') { |
|
840 | - if(!$this->access->readAttribute($member, |
|
841 | - $this->access->connection->ldapUserDisplayName, |
|
842 | - $this->access->getFilterPartForUserSearch($search))) { |
|
843 | - continue; |
|
844 | - } |
|
845 | - } |
|
846 | - // dn2username will also check if the users belong to the allowed base |
|
847 | - if($ocname = $this->access->dn2username($member)) { |
|
848 | - $groupUsers[] = $ocname; |
|
849 | - } |
|
850 | - } |
|
851 | - } |
|
852 | - |
|
853 | - $groupUsers = array_unique(array_merge($groupUsers, $primaryUsers)); |
|
854 | - natsort($groupUsers); |
|
855 | - $this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers); |
|
856 | - $groupUsers = array_slice($groupUsers, $offset, $limit); |
|
857 | - |
|
858 | - $groupUsers = array_unique(array_merge($groupUsers, $posixGroupUsers)); |
|
859 | - natsort($groupUsers); |
|
860 | - $this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers); |
|
861 | - $groupUsers = array_slice($groupUsers, $offset, $limit); |
|
862 | - |
|
863 | - $this->access->connection->writeToCache($cacheKey, $groupUsers); |
|
864 | - |
|
865 | - return $groupUsers; |
|
866 | - } |
|
867 | - |
|
868 | - /** |
|
869 | - * returns the number of users in a group, who match the search term |
|
870 | - * @param string $gid the internal group name |
|
871 | - * @param string $search optional, a search string |
|
872 | - * @return int|bool |
|
873 | - */ |
|
874 | - public function countUsersInGroup($gid, $search = '') { |
|
875 | - $cacheKey = 'countUsersInGroup-'.$gid.'-'.$search; |
|
876 | - if(!$this->enabled || !$this->groupExists($gid)) { |
|
877 | - return false; |
|
878 | - } |
|
879 | - $groupUsers = $this->access->connection->getFromCache($cacheKey); |
|
880 | - if(!is_null($groupUsers)) { |
|
881 | - return $groupUsers; |
|
882 | - } |
|
883 | - |
|
884 | - $groupDN = $this->access->groupname2dn($gid); |
|
885 | - if(!$groupDN) { |
|
886 | - // group couldn't be found, return empty result set |
|
887 | - $this->access->connection->writeToCache($cacheKey, false); |
|
888 | - return false; |
|
889 | - } |
|
890 | - |
|
891 | - $members = array_keys($this->_groupMembers($groupDN)); |
|
892 | - $primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, ''); |
|
893 | - if(!$members && $primaryUserCount === 0) { |
|
894 | - //in case users could not be retrieved, return empty result set |
|
895 | - $this->access->connection->writeToCache($cacheKey, false); |
|
896 | - return false; |
|
897 | - } |
|
898 | - |
|
899 | - if ($search === '') { |
|
900 | - $groupUsers = count($members) + $primaryUserCount; |
|
901 | - $this->access->connection->writeToCache($cacheKey, $groupUsers); |
|
902 | - return $groupUsers; |
|
903 | - } |
|
904 | - $search = $this->access->escapeFilterPart($search, true); |
|
905 | - $isMemberUid = |
|
906 | - (strtolower($this->access->connection->ldapGroupMemberAssocAttr) |
|
907 | - === 'memberuid'); |
|
908 | - |
|
909 | - //we need to apply the search filter |
|
910 | - //alternatives that need to be checked: |
|
911 | - //a) get all users by search filter and array_intersect them |
|
912 | - //b) a, but only when less than 1k 10k ?k users like it is |
|
913 | - //c) put all DNs|uids in a LDAP filter, combine with the search string |
|
914 | - // and let it count. |
|
915 | - //For now this is not important, because the only use of this method |
|
916 | - //does not supply a search string |
|
917 | - $groupUsers = array(); |
|
918 | - foreach($members as $member) { |
|
919 | - if($isMemberUid) { |
|
920 | - //we got uids, need to get their DNs to 'translate' them to user names |
|
921 | - $filter = $this->access->combineFilterWithAnd(array( |
|
922 | - str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), |
|
923 | - $this->access->getFilterPartForUserSearch($search) |
|
924 | - )); |
|
925 | - $ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1); |
|
926 | - if(count($ldap_users) < 1) { |
|
927 | - continue; |
|
928 | - } |
|
929 | - $groupUsers[] = $this->access->dn2username($ldap_users[0]); |
|
930 | - } else { |
|
931 | - //we need to apply the search filter now |
|
932 | - if(!$this->access->readAttribute($member, |
|
933 | - $this->access->connection->ldapUserDisplayName, |
|
934 | - $this->access->getFilterPartForUserSearch($search))) { |
|
935 | - continue; |
|
936 | - } |
|
937 | - // dn2username will also check if the users belong to the allowed base |
|
938 | - if($ocname = $this->access->dn2username($member)) { |
|
939 | - $groupUsers[] = $ocname; |
|
940 | - } |
|
941 | - } |
|
942 | - } |
|
943 | - |
|
944 | - //and get users that have the group as primary |
|
945 | - $primaryUsers = $this->countUsersInPrimaryGroup($groupDN, $search); |
|
946 | - |
|
947 | - return count($groupUsers) + $primaryUsers; |
|
948 | - } |
|
949 | - |
|
950 | - /** |
|
951 | - * get a list of all groups |
|
952 | - * |
|
953 | - * @param string $search |
|
954 | - * @param $limit |
|
955 | - * @param int $offset |
|
956 | - * @return array with group names |
|
957 | - * |
|
958 | - * Returns a list with all groups (used by getGroups) |
|
959 | - */ |
|
960 | - protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) { |
|
961 | - if(!$this->enabled) { |
|
962 | - return array(); |
|
963 | - } |
|
964 | - $cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset; |
|
965 | - |
|
966 | - //Check cache before driving unnecessary searches |
|
967 | - \OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG); |
|
968 | - $ldap_groups = $this->access->connection->getFromCache($cacheKey); |
|
969 | - if(!is_null($ldap_groups)) { |
|
970 | - return $ldap_groups; |
|
971 | - } |
|
972 | - |
|
973 | - // if we'd pass -1 to LDAP search, we'd end up in a Protocol |
|
974 | - // error. With a limit of 0, we get 0 results. So we pass null. |
|
975 | - if($limit <= 0) { |
|
976 | - $limit = null; |
|
977 | - } |
|
978 | - $filter = $this->access->combineFilterWithAnd(array( |
|
979 | - $this->access->connection->ldapGroupFilter, |
|
980 | - $this->access->getFilterPartForGroupSearch($search) |
|
981 | - )); |
|
982 | - \OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, \OCP\Util::DEBUG); |
|
983 | - $ldap_groups = $this->access->fetchListOfGroups($filter, |
|
984 | - array($this->access->connection->ldapGroupDisplayName, 'dn'), |
|
985 | - $limit, |
|
986 | - $offset); |
|
987 | - $ldap_groups = $this->access->nextcloudGroupNames($ldap_groups); |
|
988 | - |
|
989 | - $this->access->connection->writeToCache($cacheKey, $ldap_groups); |
|
990 | - return $ldap_groups; |
|
991 | - } |
|
992 | - |
|
993 | - /** |
|
994 | - * get a list of all groups using a paged search |
|
995 | - * |
|
996 | - * @param string $search |
|
997 | - * @param int $limit |
|
998 | - * @param int $offset |
|
999 | - * @return array with group names |
|
1000 | - * |
|
1001 | - * Returns a list with all groups |
|
1002 | - * Uses a paged search if available to override a |
|
1003 | - * server side search limit. |
|
1004 | - * (active directory has a limit of 1000 by default) |
|
1005 | - */ |
|
1006 | - public function getGroups($search = '', $limit = -1, $offset = 0) { |
|
1007 | - if(!$this->enabled) { |
|
1008 | - return array(); |
|
1009 | - } |
|
1010 | - $search = $this->access->escapeFilterPart($search, true); |
|
1011 | - $pagingSize = intval($this->access->connection->ldapPagingSize); |
|
1012 | - if (!$this->access->connection->hasPagedResultSupport || $pagingSize <= 0) { |
|
1013 | - return $this->getGroupsChunk($search, $limit, $offset); |
|
1014 | - } |
|
1015 | - $maxGroups = 100000; // limit max results (just for safety reasons) |
|
1016 | - if ($limit > -1) { |
|
1017 | - $overallLimit = min($limit + $offset, $maxGroups); |
|
1018 | - } else { |
|
1019 | - $overallLimit = $maxGroups; |
|
1020 | - } |
|
1021 | - $chunkOffset = $offset; |
|
1022 | - $allGroups = array(); |
|
1023 | - while ($chunkOffset < $overallLimit) { |
|
1024 | - $chunkLimit = min($pagingSize, $overallLimit - $chunkOffset); |
|
1025 | - $ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset); |
|
1026 | - $nread = count($ldapGroups); |
|
1027 | - \OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', \OCP\Util::DEBUG); |
|
1028 | - if ($nread) { |
|
1029 | - $allGroups = array_merge($allGroups, $ldapGroups); |
|
1030 | - $chunkOffset += $nread; |
|
1031 | - } |
|
1032 | - if ($nread < $chunkLimit) { |
|
1033 | - break; |
|
1034 | - } |
|
1035 | - } |
|
1036 | - return $allGroups; |
|
1037 | - } |
|
1038 | - |
|
1039 | - /** |
|
1040 | - * @param string $group |
|
1041 | - * @return bool |
|
1042 | - */ |
|
1043 | - public function groupMatchesFilter($group) { |
|
1044 | - return (strripos($group, $this->groupSearch) !== false); |
|
1045 | - } |
|
1046 | - |
|
1047 | - /** |
|
1048 | - * check if a group exists |
|
1049 | - * @param string $gid |
|
1050 | - * @return bool |
|
1051 | - */ |
|
1052 | - public function groupExists($gid) { |
|
1053 | - $groupExists = $this->access->connection->getFromCache('groupExists'.$gid); |
|
1054 | - if(!is_null($groupExists)) { |
|
1055 | - return (bool)$groupExists; |
|
1056 | - } |
|
1057 | - |
|
1058 | - //getting dn, if false the group does not exist. If dn, it may be mapped |
|
1059 | - //only, requires more checking. |
|
1060 | - $dn = $this->access->groupname2dn($gid); |
|
1061 | - if(!$dn) { |
|
1062 | - $this->access->connection->writeToCache('groupExists'.$gid, false); |
|
1063 | - return false; |
|
1064 | - } |
|
1065 | - |
|
1066 | - //if group really still exists, we will be able to read its objectclass |
|
1067 | - if(!is_array($this->access->readAttribute($dn, ''))) { |
|
1068 | - $this->access->connection->writeToCache('groupExists'.$gid, false); |
|
1069 | - return false; |
|
1070 | - } |
|
1071 | - |
|
1072 | - $this->access->connection->writeToCache('groupExists'.$gid, true); |
|
1073 | - return true; |
|
1074 | - } |
|
1075 | - |
|
1076 | - /** |
|
1077 | - * Check if backend implements actions |
|
1078 | - * @param int $actions bitwise-or'ed actions |
|
1079 | - * @return boolean |
|
1080 | - * |
|
1081 | - * Returns the supported actions as int to be |
|
1082 | - * compared with OC_USER_BACKEND_CREATE_USER etc. |
|
1083 | - */ |
|
1084 | - public function implementsActions($actions) { |
|
1085 | - return (bool)(\OC\Group\Backend::COUNT_USERS & $actions); |
|
1086 | - } |
|
1087 | - |
|
1088 | - /** |
|
1089 | - * Return access for LDAP interaction. |
|
1090 | - * @return Access instance of Access for LDAP interaction |
|
1091 | - */ |
|
1092 | - public function getLDAPAccess() { |
|
1093 | - return $this->access; |
|
1094 | - } |
|
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' . $gid; |
|
278 | + $groupName = $this->access->connection->getFromCache($cacheKey); |
|
279 | + if(!is_null($groupName) && isset($groupName)) { |
|
280 | + return $groupName; |
|
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 Nextcloud 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 Nextcloud 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->nextcloudUserNames($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 | + // memberof doesn't support memberuid, so skip it here. |
|
662 | + if(intval($this->access->connection->hasMemberOfFilterSupport) === 1 |
|
663 | + && intval($this->access->connection->useMemberOfToDetectMembership) === 1 |
|
664 | + && strtolower($this->access->connection->ldapGroupMemberAssocAttr) !== 'memberuid' |
|
665 | + ) { |
|
666 | + $groupDNs = $this->_getGroupDNsFromMemberOf($userDN); |
|
667 | + if (is_array($groupDNs)) { |
|
668 | + foreach ($groupDNs as $dn) { |
|
669 | + $groupName = $this->access->dn2groupname($dn); |
|
670 | + if(is_string($groupName)) { |
|
671 | + // be sure to never return false if the dn could not be |
|
672 | + // resolved to a name, for whatever reason. |
|
673 | + $groups[] = $groupName; |
|
674 | + } |
|
675 | + } |
|
676 | + } |
|
677 | + |
|
678 | + if($primaryGroup !== false) { |
|
679 | + $groups[] = $primaryGroup; |
|
680 | + } |
|
681 | + if($gidGroupName !== false) { |
|
682 | + $groups[] = $gidGroupName; |
|
683 | + } |
|
684 | + $this->access->connection->writeToCache($cacheKey, $groups); |
|
685 | + return $groups; |
|
686 | + } |
|
687 | + |
|
688 | + //uniqueMember takes DN, memberuid the uid, so we need to distinguish |
|
689 | + if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember') |
|
690 | + || (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member') |
|
691 | + ) { |
|
692 | + $uid = $userDN; |
|
693 | + } else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') { |
|
694 | + $result = $this->access->readAttribute($userDN, 'uid'); |
|
695 | + if ($result === false) { |
|
696 | + \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '. |
|
697 | + $this->access->connection->ldapHost, \OCP\Util::DEBUG); |
|
698 | + } |
|
699 | + $uid = $result[0]; |
|
700 | + } else { |
|
701 | + // just in case |
|
702 | + $uid = $userDN; |
|
703 | + } |
|
704 | + |
|
705 | + if(isset($this->cachedGroupsByMember[$uid])) { |
|
706 | + $groups = array_merge($groups, $this->cachedGroupsByMember[$uid]); |
|
707 | + } else { |
|
708 | + $groupsByMember = array_values($this->getGroupsByMember($uid)); |
|
709 | + $groupsByMember = $this->access->nextcloudGroupNames($groupsByMember); |
|
710 | + $this->cachedGroupsByMember[$uid] = $groupsByMember; |
|
711 | + $groups = array_merge($groups, $groupsByMember); |
|
712 | + } |
|
713 | + |
|
714 | + if($primaryGroup !== false) { |
|
715 | + $groups[] = $primaryGroup; |
|
716 | + } |
|
717 | + if($gidGroupName !== false) { |
|
718 | + $groups[] = $gidGroupName; |
|
719 | + } |
|
720 | + |
|
721 | + $groups = array_unique($groups, SORT_LOCALE_STRING); |
|
722 | + $this->access->connection->writeToCache($cacheKey, $groups); |
|
723 | + |
|
724 | + return $groups; |
|
725 | + } |
|
726 | + |
|
727 | + /** |
|
728 | + * @param string $dn |
|
729 | + * @param array|null &$seen |
|
730 | + * @return array |
|
731 | + */ |
|
732 | + private function getGroupsByMember($dn, &$seen = null) { |
|
733 | + if ($seen === null) { |
|
734 | + $seen = array(); |
|
735 | + } |
|
736 | + $allGroups = array(); |
|
737 | + if (array_key_exists($dn, $seen)) { |
|
738 | + // avoid loops |
|
739 | + return array(); |
|
740 | + } |
|
741 | + $seen[$dn] = true; |
|
742 | + $filter = $this->access->combineFilterWithAnd(array( |
|
743 | + $this->access->connection->ldapGroupFilter, |
|
744 | + $this->access->connection->ldapGroupMemberAssocAttr.'='.$dn |
|
745 | + )); |
|
746 | + $groups = $this->access->fetchListOfGroups($filter, |
|
747 | + array($this->access->connection->ldapGroupDisplayName, 'dn')); |
|
748 | + if (is_array($groups)) { |
|
749 | + foreach ($groups as $groupobj) { |
|
750 | + $groupDN = $groupobj['dn'][0]; |
|
751 | + $allGroups[$groupDN] = $groupobj; |
|
752 | + $nestedGroups = $this->access->connection->ldapNestedGroups; |
|
753 | + if (!empty($nestedGroups)) { |
|
754 | + $supergroups = $this->getGroupsByMember($groupDN, $seen); |
|
755 | + if (is_array($supergroups) && (count($supergroups)>0)) { |
|
756 | + $allGroups = array_merge($allGroups, $supergroups); |
|
757 | + } |
|
758 | + } |
|
759 | + } |
|
760 | + } |
|
761 | + return $allGroups; |
|
762 | + } |
|
763 | + |
|
764 | + /** |
|
765 | + * get a list of all users in a group |
|
766 | + * |
|
767 | + * @param string $gid |
|
768 | + * @param string $search |
|
769 | + * @param int $limit |
|
770 | + * @param int $offset |
|
771 | + * @return array with user ids |
|
772 | + */ |
|
773 | + public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { |
|
774 | + if(!$this->enabled) { |
|
775 | + return array(); |
|
776 | + } |
|
777 | + if(!$this->groupExists($gid)) { |
|
778 | + return array(); |
|
779 | + } |
|
780 | + $search = $this->access->escapeFilterPart($search, true); |
|
781 | + $cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset; |
|
782 | + // check for cache of the exact query |
|
783 | + $groupUsers = $this->access->connection->getFromCache($cacheKey); |
|
784 | + if(!is_null($groupUsers)) { |
|
785 | + return $groupUsers; |
|
786 | + } |
|
787 | + |
|
788 | + // check for cache of the query without limit and offset |
|
789 | + $groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search); |
|
790 | + if(!is_null($groupUsers)) { |
|
791 | + $groupUsers = array_slice($groupUsers, $offset, $limit); |
|
792 | + $this->access->connection->writeToCache($cacheKey, $groupUsers); |
|
793 | + return $groupUsers; |
|
794 | + } |
|
795 | + |
|
796 | + if($limit === -1) { |
|
797 | + $limit = null; |
|
798 | + } |
|
799 | + $groupDN = $this->access->groupname2dn($gid); |
|
800 | + if(!$groupDN) { |
|
801 | + // group couldn't be found, return empty resultset |
|
802 | + $this->access->connection->writeToCache($cacheKey, array()); |
|
803 | + return array(); |
|
804 | + } |
|
805 | + |
|
806 | + $primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset); |
|
807 | + $members = array_keys($this->_groupMembers($groupDN)); |
|
808 | + if(!$members && empty($primaryUsers)) { |
|
809 | + //in case users could not be retrieved, return empty result set |
|
810 | + $this->access->connection->writeToCache($cacheKey, array()); |
|
811 | + return array(); |
|
812 | + } |
|
813 | + |
|
814 | + $posixGroupUsers = $this->getUsersInGidNumber($groupDN, $search, $limit, $offset); |
|
815 | + $members = array_keys($this->_groupMembers($groupDN)); |
|
816 | + if(!$members && empty($posixGroupUsers)) { |
|
817 | + //in case users could not be retrieved, return empty result set |
|
818 | + $this->access->connection->writeToCache($cacheKey, []); |
|
819 | + return []; |
|
820 | + } |
|
821 | + |
|
822 | + $groupUsers = array(); |
|
823 | + $isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid'); |
|
824 | + $attrs = $this->access->userManager->getAttributes(true); |
|
825 | + foreach($members as $member) { |
|
826 | + if($isMemberUid) { |
|
827 | + //we got uids, need to get their DNs to 'translate' them to user names |
|
828 | + $filter = $this->access->combineFilterWithAnd(array( |
|
829 | + str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), |
|
830 | + $this->access->getFilterPartForUserSearch($search) |
|
831 | + )); |
|
832 | + $ldap_users = $this->access->fetchListOfUsers($filter, $attrs, 1); |
|
833 | + if(count($ldap_users) < 1) { |
|
834 | + continue; |
|
835 | + } |
|
836 | + $groupUsers[] = $this->access->dn2username($ldap_users[0]['dn'][0]); |
|
837 | + } else { |
|
838 | + //we got DNs, check if we need to filter by search or we can give back all of them |
|
839 | + if ($search !== '') { |
|
840 | + if(!$this->access->readAttribute($member, |
|
841 | + $this->access->connection->ldapUserDisplayName, |
|
842 | + $this->access->getFilterPartForUserSearch($search))) { |
|
843 | + continue; |
|
844 | + } |
|
845 | + } |
|
846 | + // dn2username will also check if the users belong to the allowed base |
|
847 | + if($ocname = $this->access->dn2username($member)) { |
|
848 | + $groupUsers[] = $ocname; |
|
849 | + } |
|
850 | + } |
|
851 | + } |
|
852 | + |
|
853 | + $groupUsers = array_unique(array_merge($groupUsers, $primaryUsers)); |
|
854 | + natsort($groupUsers); |
|
855 | + $this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers); |
|
856 | + $groupUsers = array_slice($groupUsers, $offset, $limit); |
|
857 | + |
|
858 | + $groupUsers = array_unique(array_merge($groupUsers, $posixGroupUsers)); |
|
859 | + natsort($groupUsers); |
|
860 | + $this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers); |
|
861 | + $groupUsers = array_slice($groupUsers, $offset, $limit); |
|
862 | + |
|
863 | + $this->access->connection->writeToCache($cacheKey, $groupUsers); |
|
864 | + |
|
865 | + return $groupUsers; |
|
866 | + } |
|
867 | + |
|
868 | + /** |
|
869 | + * returns the number of users in a group, who match the search term |
|
870 | + * @param string $gid the internal group name |
|
871 | + * @param string $search optional, a search string |
|
872 | + * @return int|bool |
|
873 | + */ |
|
874 | + public function countUsersInGroup($gid, $search = '') { |
|
875 | + $cacheKey = 'countUsersInGroup-'.$gid.'-'.$search; |
|
876 | + if(!$this->enabled || !$this->groupExists($gid)) { |
|
877 | + return false; |
|
878 | + } |
|
879 | + $groupUsers = $this->access->connection->getFromCache($cacheKey); |
|
880 | + if(!is_null($groupUsers)) { |
|
881 | + return $groupUsers; |
|
882 | + } |
|
883 | + |
|
884 | + $groupDN = $this->access->groupname2dn($gid); |
|
885 | + if(!$groupDN) { |
|
886 | + // group couldn't be found, return empty result set |
|
887 | + $this->access->connection->writeToCache($cacheKey, false); |
|
888 | + return false; |
|
889 | + } |
|
890 | + |
|
891 | + $members = array_keys($this->_groupMembers($groupDN)); |
|
892 | + $primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, ''); |
|
893 | + if(!$members && $primaryUserCount === 0) { |
|
894 | + //in case users could not be retrieved, return empty result set |
|
895 | + $this->access->connection->writeToCache($cacheKey, false); |
|
896 | + return false; |
|
897 | + } |
|
898 | + |
|
899 | + if ($search === '') { |
|
900 | + $groupUsers = count($members) + $primaryUserCount; |
|
901 | + $this->access->connection->writeToCache($cacheKey, $groupUsers); |
|
902 | + return $groupUsers; |
|
903 | + } |
|
904 | + $search = $this->access->escapeFilterPart($search, true); |
|
905 | + $isMemberUid = |
|
906 | + (strtolower($this->access->connection->ldapGroupMemberAssocAttr) |
|
907 | + === 'memberuid'); |
|
908 | + |
|
909 | + //we need to apply the search filter |
|
910 | + //alternatives that need to be checked: |
|
911 | + //a) get all users by search filter and array_intersect them |
|
912 | + //b) a, but only when less than 1k 10k ?k users like it is |
|
913 | + //c) put all DNs|uids in a LDAP filter, combine with the search string |
|
914 | + // and let it count. |
|
915 | + //For now this is not important, because the only use of this method |
|
916 | + //does not supply a search string |
|
917 | + $groupUsers = array(); |
|
918 | + foreach($members as $member) { |
|
919 | + if($isMemberUid) { |
|
920 | + //we got uids, need to get their DNs to 'translate' them to user names |
|
921 | + $filter = $this->access->combineFilterWithAnd(array( |
|
922 | + str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), |
|
923 | + $this->access->getFilterPartForUserSearch($search) |
|
924 | + )); |
|
925 | + $ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1); |
|
926 | + if(count($ldap_users) < 1) { |
|
927 | + continue; |
|
928 | + } |
|
929 | + $groupUsers[] = $this->access->dn2username($ldap_users[0]); |
|
930 | + } else { |
|
931 | + //we need to apply the search filter now |
|
932 | + if(!$this->access->readAttribute($member, |
|
933 | + $this->access->connection->ldapUserDisplayName, |
|
934 | + $this->access->getFilterPartForUserSearch($search))) { |
|
935 | + continue; |
|
936 | + } |
|
937 | + // dn2username will also check if the users belong to the allowed base |
|
938 | + if($ocname = $this->access->dn2username($member)) { |
|
939 | + $groupUsers[] = $ocname; |
|
940 | + } |
|
941 | + } |
|
942 | + } |
|
943 | + |
|
944 | + //and get users that have the group as primary |
|
945 | + $primaryUsers = $this->countUsersInPrimaryGroup($groupDN, $search); |
|
946 | + |
|
947 | + return count($groupUsers) + $primaryUsers; |
|
948 | + } |
|
949 | + |
|
950 | + /** |
|
951 | + * get a list of all groups |
|
952 | + * |
|
953 | + * @param string $search |
|
954 | + * @param $limit |
|
955 | + * @param int $offset |
|
956 | + * @return array with group names |
|
957 | + * |
|
958 | + * Returns a list with all groups (used by getGroups) |
|
959 | + */ |
|
960 | + protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) { |
|
961 | + if(!$this->enabled) { |
|
962 | + return array(); |
|
963 | + } |
|
964 | + $cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset; |
|
965 | + |
|
966 | + //Check cache before driving unnecessary searches |
|
967 | + \OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG); |
|
968 | + $ldap_groups = $this->access->connection->getFromCache($cacheKey); |
|
969 | + if(!is_null($ldap_groups)) { |
|
970 | + return $ldap_groups; |
|
971 | + } |
|
972 | + |
|
973 | + // if we'd pass -1 to LDAP search, we'd end up in a Protocol |
|
974 | + // error. With a limit of 0, we get 0 results. So we pass null. |
|
975 | + if($limit <= 0) { |
|
976 | + $limit = null; |
|
977 | + } |
|
978 | + $filter = $this->access->combineFilterWithAnd(array( |
|
979 | + $this->access->connection->ldapGroupFilter, |
|
980 | + $this->access->getFilterPartForGroupSearch($search) |
|
981 | + )); |
|
982 | + \OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, \OCP\Util::DEBUG); |
|
983 | + $ldap_groups = $this->access->fetchListOfGroups($filter, |
|
984 | + array($this->access->connection->ldapGroupDisplayName, 'dn'), |
|
985 | + $limit, |
|
986 | + $offset); |
|
987 | + $ldap_groups = $this->access->nextcloudGroupNames($ldap_groups); |
|
988 | + |
|
989 | + $this->access->connection->writeToCache($cacheKey, $ldap_groups); |
|
990 | + return $ldap_groups; |
|
991 | + } |
|
992 | + |
|
993 | + /** |
|
994 | + * get a list of all groups using a paged search |
|
995 | + * |
|
996 | + * @param string $search |
|
997 | + * @param int $limit |
|
998 | + * @param int $offset |
|
999 | + * @return array with group names |
|
1000 | + * |
|
1001 | + * Returns a list with all groups |
|
1002 | + * Uses a paged search if available to override a |
|
1003 | + * server side search limit. |
|
1004 | + * (active directory has a limit of 1000 by default) |
|
1005 | + */ |
|
1006 | + public function getGroups($search = '', $limit = -1, $offset = 0) { |
|
1007 | + if(!$this->enabled) { |
|
1008 | + return array(); |
|
1009 | + } |
|
1010 | + $search = $this->access->escapeFilterPart($search, true); |
|
1011 | + $pagingSize = intval($this->access->connection->ldapPagingSize); |
|
1012 | + if (!$this->access->connection->hasPagedResultSupport || $pagingSize <= 0) { |
|
1013 | + return $this->getGroupsChunk($search, $limit, $offset); |
|
1014 | + } |
|
1015 | + $maxGroups = 100000; // limit max results (just for safety reasons) |
|
1016 | + if ($limit > -1) { |
|
1017 | + $overallLimit = min($limit + $offset, $maxGroups); |
|
1018 | + } else { |
|
1019 | + $overallLimit = $maxGroups; |
|
1020 | + } |
|
1021 | + $chunkOffset = $offset; |
|
1022 | + $allGroups = array(); |
|
1023 | + while ($chunkOffset < $overallLimit) { |
|
1024 | + $chunkLimit = min($pagingSize, $overallLimit - $chunkOffset); |
|
1025 | + $ldapGroups = $this->getGroupsChunk($search, $chunkLimit, $chunkOffset); |
|
1026 | + $nread = count($ldapGroups); |
|
1027 | + \OCP\Util::writeLog('user_ldap', 'getGroups('.$search.'): read '.$nread.' at offset '.$chunkOffset.' (limit: '.$chunkLimit.')', \OCP\Util::DEBUG); |
|
1028 | + if ($nread) { |
|
1029 | + $allGroups = array_merge($allGroups, $ldapGroups); |
|
1030 | + $chunkOffset += $nread; |
|
1031 | + } |
|
1032 | + if ($nread < $chunkLimit) { |
|
1033 | + break; |
|
1034 | + } |
|
1035 | + } |
|
1036 | + return $allGroups; |
|
1037 | + } |
|
1038 | + |
|
1039 | + /** |
|
1040 | + * @param string $group |
|
1041 | + * @return bool |
|
1042 | + */ |
|
1043 | + public function groupMatchesFilter($group) { |
|
1044 | + return (strripos($group, $this->groupSearch) !== false); |
|
1045 | + } |
|
1046 | + |
|
1047 | + /** |
|
1048 | + * check if a group exists |
|
1049 | + * @param string $gid |
|
1050 | + * @return bool |
|
1051 | + */ |
|
1052 | + public function groupExists($gid) { |
|
1053 | + $groupExists = $this->access->connection->getFromCache('groupExists'.$gid); |
|
1054 | + if(!is_null($groupExists)) { |
|
1055 | + return (bool)$groupExists; |
|
1056 | + } |
|
1057 | + |
|
1058 | + //getting dn, if false the group does not exist. If dn, it may be mapped |
|
1059 | + //only, requires more checking. |
|
1060 | + $dn = $this->access->groupname2dn($gid); |
|
1061 | + if(!$dn) { |
|
1062 | + $this->access->connection->writeToCache('groupExists'.$gid, false); |
|
1063 | + return false; |
|
1064 | + } |
|
1065 | + |
|
1066 | + //if group really still exists, we will be able to read its objectclass |
|
1067 | + if(!is_array($this->access->readAttribute($dn, ''))) { |
|
1068 | + $this->access->connection->writeToCache('groupExists'.$gid, false); |
|
1069 | + return false; |
|
1070 | + } |
|
1071 | + |
|
1072 | + $this->access->connection->writeToCache('groupExists'.$gid, true); |
|
1073 | + return true; |
|
1074 | + } |
|
1075 | + |
|
1076 | + /** |
|
1077 | + * Check if backend implements actions |
|
1078 | + * @param int $actions bitwise-or'ed actions |
|
1079 | + * @return boolean |
|
1080 | + * |
|
1081 | + * Returns the supported actions as int to be |
|
1082 | + * compared with OC_USER_BACKEND_CREATE_USER etc. |
|
1083 | + */ |
|
1084 | + public function implementsActions($actions) { |
|
1085 | + return (bool)(\OC\Group\Backend::COUNT_USERS & $actions); |
|
1086 | + } |
|
1087 | + |
|
1088 | + /** |
|
1089 | + * Return access for LDAP interaction. |
|
1090 | + * @return Access instance of Access for LDAP interaction |
|
1091 | + */ |
|
1092 | + public function getLDAPAccess() { |
|
1093 | + return $this->access; |
|
1094 | + } |
|
1095 | 1095 | } |
@@ -57,7 +57,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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) { |
@@ -274,9 +274,9 @@ discard block |
||
274 | 274 | * @return string|bool |
275 | 275 | */ |
276 | 276 | public function gidNumber2Name($gid, $dn) { |
277 | - $cacheKey = 'gidNumberToName' . $gid; |
|
277 | + $cacheKey = 'gidNumberToName'.$gid; |
|
278 | 278 | $groupName = $this->access->connection->getFromCache($cacheKey); |
279 | - if(!is_null($groupName) && isset($groupName)) { |
|
279 | + if (!is_null($groupName) && isset($groupName)) { |
|
280 | 280 | return $groupName; |
281 | 281 | } |
282 | 282 | |
@@ -284,10 +284,10 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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,7 +651,7 @@ discard block |
||
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 | } |
@@ -659,7 +659,7 @@ discard block |
||
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 | 661 | // memberof doesn't support memberuid, so skip it here. |
662 | - if(intval($this->access->connection->hasMemberOfFilterSupport) === 1 |
|
662 | + if (intval($this->access->connection->hasMemberOfFilterSupport) === 1 |
|
663 | 663 | && intval($this->access->connection->useMemberOfToDetectMembership) === 1 |
664 | 664 | && strtolower($this->access->connection->ldapGroupMemberAssocAttr) !== 'memberuid' |
665 | 665 | ) { |
@@ -667,7 +667,7 @@ discard block |
||
667 | 667 | if (is_array($groupDNs)) { |
668 | 668 | foreach ($groupDNs as $dn) { |
669 | 669 | $groupName = $this->access->dn2groupname($dn); |
670 | - if(is_string($groupName)) { |
|
670 | + if (is_string($groupName)) { |
|
671 | 671 | // be sure to never return false if the dn could not be |
672 | 672 | // resolved to a name, for whatever reason. |
673 | 673 | $groups[] = $groupName; |
@@ -675,10 +675,10 @@ discard block |
||
675 | 675 | } |
676 | 676 | } |
677 | 677 | |
678 | - if($primaryGroup !== false) { |
|
678 | + if ($primaryGroup !== false) { |
|
679 | 679 | $groups[] = $primaryGroup; |
680 | 680 | } |
681 | - if($gidGroupName !== false) { |
|
681 | + if ($gidGroupName !== false) { |
|
682 | 682 | $groups[] = $gidGroupName; |
683 | 683 | } |
684 | 684 | $this->access->connection->writeToCache($cacheKey, $groups); |
@@ -686,14 +686,14 @@ discard block |
||
686 | 686 | } |
687 | 687 | |
688 | 688 | //uniqueMember takes DN, memberuid the uid, so we need to distinguish |
689 | - if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember') |
|
689 | + if ((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember') |
|
690 | 690 | || (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member') |
691 | 691 | ) { |
692 | 692 | $uid = $userDN; |
693 | - } else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') { |
|
693 | + } else if (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') { |
|
694 | 694 | $result = $this->access->readAttribute($userDN, 'uid'); |
695 | 695 | if ($result === false) { |
696 | - \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN ' . $userDN . ' on '. |
|
696 | + \OCP\Util::writeLog('user_ldap', 'No uid attribute found for DN '.$userDN.' on '. |
|
697 | 697 | $this->access->connection->ldapHost, \OCP\Util::DEBUG); |
698 | 698 | } |
699 | 699 | $uid = $result[0]; |
@@ -702,7 +702,7 @@ discard block |
||
702 | 702 | $uid = $userDN; |
703 | 703 | } |
704 | 704 | |
705 | - if(isset($this->cachedGroupsByMember[$uid])) { |
|
705 | + if (isset($this->cachedGroupsByMember[$uid])) { |
|
706 | 706 | $groups = array_merge($groups, $this->cachedGroupsByMember[$uid]); |
707 | 707 | } else { |
708 | 708 | $groupsByMember = array_values($this->getGroupsByMember($uid)); |
@@ -711,10 +711,10 @@ discard block |
||
711 | 711 | $groups = array_merge($groups, $groupsByMember); |
712 | 712 | } |
713 | 713 | |
714 | - if($primaryGroup !== false) { |
|
714 | + if ($primaryGroup !== false) { |
|
715 | 715 | $groups[] = $primaryGroup; |
716 | 716 | } |
717 | - if($gidGroupName !== false) { |
|
717 | + if ($gidGroupName !== false) { |
|
718 | 718 | $groups[] = $gidGroupName; |
719 | 719 | } |
720 | 720 | |
@@ -752,7 +752,7 @@ discard block |
||
752 | 752 | $nestedGroups = $this->access->connection->ldapNestedGroups; |
753 | 753 | if (!empty($nestedGroups)) { |
754 | 754 | $supergroups = $this->getGroupsByMember($groupDN, $seen); |
755 | - if (is_array($supergroups) && (count($supergroups)>0)) { |
|
755 | + if (is_array($supergroups) && (count($supergroups) > 0)) { |
|
756 | 756 | $allGroups = array_merge($allGroups, $supergroups); |
757 | 757 | } |
758 | 758 | } |
@@ -771,33 +771,33 @@ discard block |
||
771 | 771 | * @return array with user ids |
772 | 772 | */ |
773 | 773 | public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { |
774 | - if(!$this->enabled) { |
|
774 | + if (!$this->enabled) { |
|
775 | 775 | return array(); |
776 | 776 | } |
777 | - if(!$this->groupExists($gid)) { |
|
777 | + if (!$this->groupExists($gid)) { |
|
778 | 778 | return array(); |
779 | 779 | } |
780 | 780 | $search = $this->access->escapeFilterPart($search, true); |
781 | 781 | $cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset; |
782 | 782 | // check for cache of the exact query |
783 | 783 | $groupUsers = $this->access->connection->getFromCache($cacheKey); |
784 | - if(!is_null($groupUsers)) { |
|
784 | + if (!is_null($groupUsers)) { |
|
785 | 785 | return $groupUsers; |
786 | 786 | } |
787 | 787 | |
788 | 788 | // check for cache of the query without limit and offset |
789 | 789 | $groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search); |
790 | - if(!is_null($groupUsers)) { |
|
790 | + if (!is_null($groupUsers)) { |
|
791 | 791 | $groupUsers = array_slice($groupUsers, $offset, $limit); |
792 | 792 | $this->access->connection->writeToCache($cacheKey, $groupUsers); |
793 | 793 | return $groupUsers; |
794 | 794 | } |
795 | 795 | |
796 | - if($limit === -1) { |
|
796 | + if ($limit === -1) { |
|
797 | 797 | $limit = null; |
798 | 798 | } |
799 | 799 | $groupDN = $this->access->groupname2dn($gid); |
800 | - if(!$groupDN) { |
|
800 | + if (!$groupDN) { |
|
801 | 801 | // group couldn't be found, return empty resultset |
802 | 802 | $this->access->connection->writeToCache($cacheKey, array()); |
803 | 803 | return array(); |
@@ -805,7 +805,7 @@ discard block |
||
805 | 805 | |
806 | 806 | $primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset); |
807 | 807 | $members = array_keys($this->_groupMembers($groupDN)); |
808 | - if(!$members && empty($primaryUsers)) { |
|
808 | + if (!$members && empty($primaryUsers)) { |
|
809 | 809 | //in case users could not be retrieved, return empty result set |
810 | 810 | $this->access->connection->writeToCache($cacheKey, array()); |
811 | 811 | return array(); |
@@ -813,7 +813,7 @@ discard block |
||
813 | 813 | |
814 | 814 | $posixGroupUsers = $this->getUsersInGidNumber($groupDN, $search, $limit, $offset); |
815 | 815 | $members = array_keys($this->_groupMembers($groupDN)); |
816 | - if(!$members && empty($posixGroupUsers)) { |
|
816 | + if (!$members && empty($posixGroupUsers)) { |
|
817 | 817 | //in case users could not be retrieved, return empty result set |
818 | 818 | $this->access->connection->writeToCache($cacheKey, []); |
819 | 819 | return []; |
@@ -822,29 +822,29 @@ discard block |
||
822 | 822 | $groupUsers = array(); |
823 | 823 | $isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid'); |
824 | 824 | $attrs = $this->access->userManager->getAttributes(true); |
825 | - foreach($members as $member) { |
|
826 | - if($isMemberUid) { |
|
825 | + foreach ($members as $member) { |
|
826 | + if ($isMemberUid) { |
|
827 | 827 | //we got uids, need to get their DNs to 'translate' them to user names |
828 | 828 | $filter = $this->access->combineFilterWithAnd(array( |
829 | 829 | str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), |
830 | 830 | $this->access->getFilterPartForUserSearch($search) |
831 | 831 | )); |
832 | 832 | $ldap_users = $this->access->fetchListOfUsers($filter, $attrs, 1); |
833 | - if(count($ldap_users) < 1) { |
|
833 | + if (count($ldap_users) < 1) { |
|
834 | 834 | continue; |
835 | 835 | } |
836 | 836 | $groupUsers[] = $this->access->dn2username($ldap_users[0]['dn'][0]); |
837 | 837 | } else { |
838 | 838 | //we got DNs, check if we need to filter by search or we can give back all of them |
839 | 839 | if ($search !== '') { |
840 | - if(!$this->access->readAttribute($member, |
|
840 | + if (!$this->access->readAttribute($member, |
|
841 | 841 | $this->access->connection->ldapUserDisplayName, |
842 | 842 | $this->access->getFilterPartForUserSearch($search))) { |
843 | 843 | continue; |
844 | 844 | } |
845 | 845 | } |
846 | 846 | // dn2username will also check if the users belong to the allowed base |
847 | - if($ocname = $this->access->dn2username($member)) { |
|
847 | + if ($ocname = $this->access->dn2username($member)) { |
|
848 | 848 | $groupUsers[] = $ocname; |
849 | 849 | } |
850 | 850 | } |
@@ -873,16 +873,16 @@ discard block |
||
873 | 873 | */ |
874 | 874 | public function countUsersInGroup($gid, $search = '') { |
875 | 875 | $cacheKey = 'countUsersInGroup-'.$gid.'-'.$search; |
876 | - if(!$this->enabled || !$this->groupExists($gid)) { |
|
876 | + if (!$this->enabled || !$this->groupExists($gid)) { |
|
877 | 877 | return false; |
878 | 878 | } |
879 | 879 | $groupUsers = $this->access->connection->getFromCache($cacheKey); |
880 | - if(!is_null($groupUsers)) { |
|
880 | + if (!is_null($groupUsers)) { |
|
881 | 881 | return $groupUsers; |
882 | 882 | } |
883 | 883 | |
884 | 884 | $groupDN = $this->access->groupname2dn($gid); |
885 | - if(!$groupDN) { |
|
885 | + if (!$groupDN) { |
|
886 | 886 | // group couldn't be found, return empty result set |
887 | 887 | $this->access->connection->writeToCache($cacheKey, false); |
888 | 888 | return false; |
@@ -890,7 +890,7 @@ discard block |
||
890 | 890 | |
891 | 891 | $members = array_keys($this->_groupMembers($groupDN)); |
892 | 892 | $primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, ''); |
893 | - if(!$members && $primaryUserCount === 0) { |
|
893 | + if (!$members && $primaryUserCount === 0) { |
|
894 | 894 | //in case users could not be retrieved, return empty result set |
895 | 895 | $this->access->connection->writeToCache($cacheKey, false); |
896 | 896 | return false; |
@@ -915,27 +915,27 @@ discard block |
||
915 | 915 | //For now this is not important, because the only use of this method |
916 | 916 | //does not supply a search string |
917 | 917 | $groupUsers = array(); |
918 | - foreach($members as $member) { |
|
919 | - if($isMemberUid) { |
|
918 | + foreach ($members as $member) { |
|
919 | + if ($isMemberUid) { |
|
920 | 920 | //we got uids, need to get their DNs to 'translate' them to user names |
921 | 921 | $filter = $this->access->combineFilterWithAnd(array( |
922 | 922 | str_replace('%uid', $member, $this->access->connection->ldapLoginFilter), |
923 | 923 | $this->access->getFilterPartForUserSearch($search) |
924 | 924 | )); |
925 | 925 | $ldap_users = $this->access->fetchListOfUsers($filter, 'dn', 1); |
926 | - if(count($ldap_users) < 1) { |
|
926 | + if (count($ldap_users) < 1) { |
|
927 | 927 | continue; |
928 | 928 | } |
929 | 929 | $groupUsers[] = $this->access->dn2username($ldap_users[0]); |
930 | 930 | } else { |
931 | 931 | //we need to apply the search filter now |
932 | - if(!$this->access->readAttribute($member, |
|
932 | + if (!$this->access->readAttribute($member, |
|
933 | 933 | $this->access->connection->ldapUserDisplayName, |
934 | 934 | $this->access->getFilterPartForUserSearch($search))) { |
935 | 935 | continue; |
936 | 936 | } |
937 | 937 | // dn2username will also check if the users belong to the allowed base |
938 | - if($ocname = $this->access->dn2username($member)) { |
|
938 | + if ($ocname = $this->access->dn2username($member)) { |
|
939 | 939 | $groupUsers[] = $ocname; |
940 | 940 | } |
941 | 941 | } |
@@ -958,7 +958,7 @@ discard block |
||
958 | 958 | * Returns a list with all groups (used by getGroups) |
959 | 959 | */ |
960 | 960 | protected function getGroupsChunk($search = '', $limit = -1, $offset = 0) { |
961 | - if(!$this->enabled) { |
|
961 | + if (!$this->enabled) { |
|
962 | 962 | return array(); |
963 | 963 | } |
964 | 964 | $cacheKey = 'getGroups-'.$search.'-'.$limit.'-'.$offset; |
@@ -966,13 +966,13 @@ discard block |
||
966 | 966 | //Check cache before driving unnecessary searches |
967 | 967 | \OCP\Util::writeLog('user_ldap', 'getGroups '.$cacheKey, \OCP\Util::DEBUG); |
968 | 968 | $ldap_groups = $this->access->connection->getFromCache($cacheKey); |
969 | - if(!is_null($ldap_groups)) { |
|
969 | + if (!is_null($ldap_groups)) { |
|
970 | 970 | return $ldap_groups; |
971 | 971 | } |
972 | 972 | |
973 | 973 | // if we'd pass -1 to LDAP search, we'd end up in a Protocol |
974 | 974 | // error. With a limit of 0, we get 0 results. So we pass null. |
975 | - if($limit <= 0) { |
|
975 | + if ($limit <= 0) { |
|
976 | 976 | $limit = null; |
977 | 977 | } |
978 | 978 | $filter = $this->access->combineFilterWithAnd(array( |
@@ -1004,7 +1004,7 @@ discard block |
||
1004 | 1004 | * (active directory has a limit of 1000 by default) |
1005 | 1005 | */ |
1006 | 1006 | public function getGroups($search = '', $limit = -1, $offset = 0) { |
1007 | - if(!$this->enabled) { |
|
1007 | + if (!$this->enabled) { |
|
1008 | 1008 | return array(); |
1009 | 1009 | } |
1010 | 1010 | $search = $this->access->escapeFilterPart($search, true); |
@@ -1051,20 +1051,20 @@ discard block |
||
1051 | 1051 | */ |
1052 | 1052 | public function groupExists($gid) { |
1053 | 1053 | $groupExists = $this->access->connection->getFromCache('groupExists'.$gid); |
1054 | - if(!is_null($groupExists)) { |
|
1055 | - return (bool)$groupExists; |
|
1054 | + if (!is_null($groupExists)) { |
|
1055 | + return (bool) $groupExists; |
|
1056 | 1056 | } |
1057 | 1057 | |
1058 | 1058 | //getting dn, if false the group does not exist. If dn, it may be mapped |
1059 | 1059 | //only, requires more checking. |
1060 | 1060 | $dn = $this->access->groupname2dn($gid); |
1061 | - if(!$dn) { |
|
1061 | + if (!$dn) { |
|
1062 | 1062 | $this->access->connection->writeToCache('groupExists'.$gid, false); |
1063 | 1063 | return false; |
1064 | 1064 | } |
1065 | 1065 | |
1066 | 1066 | //if group really still exists, we will be able to read its objectclass |
1067 | - if(!is_array($this->access->readAttribute($dn, ''))) { |
|
1067 | + if (!is_array($this->access->readAttribute($dn, ''))) { |
|
1068 | 1068 | $this->access->connection->writeToCache('groupExists'.$gid, false); |
1069 | 1069 | return false; |
1070 | 1070 | } |
@@ -1082,7 +1082,7 @@ discard block |
||
1082 | 1082 | * compared with OC_USER_BACKEND_CREATE_USER etc. |
1083 | 1083 | */ |
1084 | 1084 | public function implementsActions($actions) { |
1085 | - return (bool)(\OC\Group\Backend::COUNT_USERS & $actions); |
|
1085 | + return (bool) (\OC\Group\Backend::COUNT_USERS & $actions); |
|
1086 | 1086 | } |
1087 | 1087 | |
1088 | 1088 | /** |
@@ -38,1324 +38,1324 @@ |
||
38 | 38 | use OC\ServerNotAvailableException; |
39 | 39 | |
40 | 40 | class Wizard extends LDAPUtility { |
41 | - /** @var \OCP\IL10N */ |
|
42 | - static protected $l; |
|
43 | - protected $access; |
|
44 | - protected $cr; |
|
45 | - protected $configuration; |
|
46 | - protected $result; |
|
47 | - protected $resultCache = array(); |
|
48 | - |
|
49 | - const LRESULT_PROCESSED_OK = 2; |
|
50 | - const LRESULT_PROCESSED_INVALID = 3; |
|
51 | - const LRESULT_PROCESSED_SKIP = 4; |
|
52 | - |
|
53 | - const LFILTER_LOGIN = 2; |
|
54 | - const LFILTER_USER_LIST = 3; |
|
55 | - const LFILTER_GROUP_LIST = 4; |
|
56 | - |
|
57 | - const LFILTER_MODE_ASSISTED = 2; |
|
58 | - const LFILTER_MODE_RAW = 1; |
|
59 | - |
|
60 | - const LDAP_NW_TIMEOUT = 4; |
|
61 | - |
|
62 | - /** |
|
63 | - * Constructor |
|
64 | - * @param Configuration $configuration an instance of Configuration |
|
65 | - * @param ILDAPWrapper $ldap an instance of ILDAPWrapper |
|
66 | - * @param Access $access |
|
67 | - */ |
|
68 | - public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) { |
|
69 | - parent::__construct($ldap); |
|
70 | - $this->configuration = $configuration; |
|
71 | - if(is_null(Wizard::$l)) { |
|
72 | - Wizard::$l = \OC::$server->getL10N('user_ldap'); |
|
73 | - } |
|
74 | - $this->access = $access; |
|
75 | - $this->result = new WizardResult(); |
|
76 | - } |
|
77 | - |
|
78 | - public function __destruct() { |
|
79 | - if($this->result->hasChanges()) { |
|
80 | - $this->configuration->saveConfiguration(); |
|
81 | - } |
|
82 | - } |
|
83 | - |
|
84 | - /** |
|
85 | - * counts entries in the LDAP directory |
|
86 | - * |
|
87 | - * @param string $filter the LDAP search filter |
|
88 | - * @param string $type a string being either 'users' or 'groups'; |
|
89 | - * @return bool|int |
|
90 | - * @throws \Exception |
|
91 | - */ |
|
92 | - public function countEntries($filter, $type) { |
|
93 | - $reqs = array('ldapHost', 'ldapPort', 'ldapBase'); |
|
94 | - if($type === 'users') { |
|
95 | - $reqs[] = 'ldapUserFilter'; |
|
96 | - } |
|
97 | - if(!$this->checkRequirements($reqs)) { |
|
98 | - throw new \Exception('Requirements not met', 400); |
|
99 | - } |
|
100 | - |
|
101 | - $attr = array('dn'); // default |
|
102 | - $limit = 1001; |
|
103 | - if($type === 'groups') { |
|
104 | - $result = $this->access->countGroups($filter, $attr, $limit); |
|
105 | - } else if($type === 'users') { |
|
106 | - $result = $this->access->countUsers($filter, $attr, $limit); |
|
107 | - } else if ($type === 'objects') { |
|
108 | - $result = $this->access->countObjects($limit); |
|
109 | - } else { |
|
110 | - throw new \Exception('internal error: invalid object type', 500); |
|
111 | - } |
|
112 | - |
|
113 | - return $result; |
|
114 | - } |
|
115 | - |
|
116 | - /** |
|
117 | - * formats the return value of a count operation to the string to be |
|
118 | - * inserted. |
|
119 | - * |
|
120 | - * @param bool|int $count |
|
121 | - * @return int|string |
|
122 | - */ |
|
123 | - private function formatCountResult($count) { |
|
124 | - $formatted = ($count !== false) ? $count : 0; |
|
125 | - if($formatted > 1000) { |
|
126 | - $formatted = '> 1000'; |
|
127 | - } |
|
128 | - return $formatted; |
|
129 | - } |
|
130 | - |
|
131 | - public function countGroups() { |
|
132 | - $filter = $this->configuration->ldapGroupFilter; |
|
133 | - |
|
134 | - if(empty($filter)) { |
|
135 | - $output = self::$l->n('%s group found', '%s groups found', 0, array(0)); |
|
136 | - $this->result->addChange('ldap_group_count', $output); |
|
137 | - return $this->result; |
|
138 | - } |
|
139 | - |
|
140 | - try { |
|
141 | - $groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups')); |
|
142 | - } catch (\Exception $e) { |
|
143 | - //400 can be ignored, 500 is forwarded |
|
144 | - if($e->getCode() === 500) { |
|
145 | - throw $e; |
|
146 | - } |
|
147 | - return false; |
|
148 | - } |
|
149 | - $output = self::$l->n('%s group found', '%s groups found', $groupsTotal, array($groupsTotal)); |
|
150 | - $this->result->addChange('ldap_group_count', $output); |
|
151 | - return $this->result; |
|
152 | - } |
|
153 | - |
|
154 | - /** |
|
155 | - * @return WizardResult |
|
156 | - * @throws \Exception |
|
157 | - */ |
|
158 | - public function countUsers() { |
|
159 | - $filter = $this->access->getFilterForUserCount(); |
|
160 | - |
|
161 | - $usersTotal = $this->formatCountResult($this->countEntries($filter, 'users')); |
|
162 | - $output = self::$l->n('%s user found', '%s users found', $usersTotal, array($usersTotal)); |
|
163 | - $this->result->addChange('ldap_user_count', $output); |
|
164 | - return $this->result; |
|
165 | - } |
|
166 | - |
|
167 | - /** |
|
168 | - * counts any objects in the currently set base dn |
|
169 | - * |
|
170 | - * @return WizardResult |
|
171 | - * @throws \Exception |
|
172 | - */ |
|
173 | - public function countInBaseDN() { |
|
174 | - // we don't need to provide a filter in this case |
|
175 | - $total = $this->countEntries(null, 'objects'); |
|
176 | - if($total === false) { |
|
177 | - throw new \Exception('invalid results received'); |
|
178 | - } |
|
179 | - $this->result->addChange('ldap_test_base', $total); |
|
180 | - return $this->result; |
|
181 | - } |
|
182 | - |
|
183 | - /** |
|
184 | - * counts users with a specified attribute |
|
185 | - * @param string $attr |
|
186 | - * @param bool $existsCheck |
|
187 | - * @return int|bool |
|
188 | - */ |
|
189 | - public function countUsersWithAttribute($attr, $existsCheck = false) { |
|
190 | - if(!$this->checkRequirements(array('ldapHost', |
|
191 | - 'ldapPort', |
|
192 | - 'ldapBase', |
|
193 | - 'ldapUserFilter', |
|
194 | - ))) { |
|
195 | - return false; |
|
196 | - } |
|
197 | - |
|
198 | - $filter = $this->access->combineFilterWithAnd(array( |
|
199 | - $this->configuration->ldapUserFilter, |
|
200 | - $attr . '=*' |
|
201 | - )); |
|
202 | - |
|
203 | - $limit = ($existsCheck === false) ? null : 1; |
|
204 | - |
|
205 | - return $this->access->countUsers($filter, array('dn'), $limit); |
|
206 | - } |
|
207 | - |
|
208 | - /** |
|
209 | - * detects the display name attribute. If a setting is already present that |
|
210 | - * returns at least one hit, the detection will be canceled. |
|
211 | - * @return WizardResult|bool |
|
212 | - * @throws \Exception |
|
213 | - */ |
|
214 | - public function detectUserDisplayNameAttribute() { |
|
215 | - if(!$this->checkRequirements(array('ldapHost', |
|
216 | - 'ldapPort', |
|
217 | - 'ldapBase', |
|
218 | - 'ldapUserFilter', |
|
219 | - ))) { |
|
220 | - return false; |
|
221 | - } |
|
222 | - |
|
223 | - $attr = $this->configuration->ldapUserDisplayName; |
|
224 | - if ($attr !== '' && $attr !== 'displayName') { |
|
225 | - // most likely not the default value with upper case N, |
|
226 | - // verify it still produces a result |
|
227 | - $count = intval($this->countUsersWithAttribute($attr, true)); |
|
228 | - if($count > 0) { |
|
229 | - //no change, but we sent it back to make sure the user interface |
|
230 | - //is still correct, even if the ajax call was cancelled meanwhile |
|
231 | - $this->result->addChange('ldap_display_name', $attr); |
|
232 | - return $this->result; |
|
233 | - } |
|
234 | - } |
|
235 | - |
|
236 | - // first attribute that has at least one result wins |
|
237 | - $displayNameAttrs = array('displayname', 'cn'); |
|
238 | - foreach ($displayNameAttrs as $attr) { |
|
239 | - $count = intval($this->countUsersWithAttribute($attr, true)); |
|
240 | - |
|
241 | - if($count > 0) { |
|
242 | - $this->applyFind('ldap_display_name', $attr); |
|
243 | - return $this->result; |
|
244 | - } |
|
245 | - }; |
|
246 | - |
|
247 | - throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced ldap settings.')); |
|
248 | - } |
|
249 | - |
|
250 | - /** |
|
251 | - * detects the most often used email attribute for users applying to the |
|
252 | - * user list filter. If a setting is already present that returns at least |
|
253 | - * one hit, the detection will be canceled. |
|
254 | - * @return WizardResult|bool |
|
255 | - */ |
|
256 | - public function detectEmailAttribute() { |
|
257 | - if(!$this->checkRequirements(array('ldapHost', |
|
258 | - 'ldapPort', |
|
259 | - 'ldapBase', |
|
260 | - 'ldapUserFilter', |
|
261 | - ))) { |
|
262 | - return false; |
|
263 | - } |
|
264 | - |
|
265 | - $attr = $this->configuration->ldapEmailAttribute; |
|
266 | - if ($attr !== '') { |
|
267 | - $count = intval($this->countUsersWithAttribute($attr, true)); |
|
268 | - if($count > 0) { |
|
269 | - return false; |
|
270 | - } |
|
271 | - $writeLog = true; |
|
272 | - } else { |
|
273 | - $writeLog = false; |
|
274 | - } |
|
275 | - |
|
276 | - $emailAttributes = array('mail', 'mailPrimaryAddress'); |
|
277 | - $winner = ''; |
|
278 | - $maxUsers = 0; |
|
279 | - foreach($emailAttributes as $attr) { |
|
280 | - $count = $this->countUsersWithAttribute($attr); |
|
281 | - if($count > $maxUsers) { |
|
282 | - $maxUsers = $count; |
|
283 | - $winner = $attr; |
|
284 | - } |
|
285 | - } |
|
286 | - |
|
287 | - if($winner !== '') { |
|
288 | - $this->applyFind('ldap_email_attr', $winner); |
|
289 | - if($writeLog) { |
|
290 | - \OCP\Util::writeLog('user_ldap', 'The mail attribute has ' . |
|
291 | - 'automatically been reset, because the original value ' . |
|
292 | - 'did not return any results.', \OCP\Util::INFO); |
|
293 | - } |
|
294 | - } |
|
295 | - |
|
296 | - return $this->result; |
|
297 | - } |
|
298 | - |
|
299 | - /** |
|
300 | - * @return WizardResult |
|
301 | - * @throws \Exception |
|
302 | - */ |
|
303 | - public function determineAttributes() { |
|
304 | - if(!$this->checkRequirements(array('ldapHost', |
|
305 | - 'ldapPort', |
|
306 | - 'ldapBase', |
|
307 | - 'ldapUserFilter', |
|
308 | - ))) { |
|
309 | - return false; |
|
310 | - } |
|
311 | - |
|
312 | - $attributes = $this->getUserAttributes(); |
|
313 | - |
|
314 | - natcasesort($attributes); |
|
315 | - $attributes = array_values($attributes); |
|
316 | - |
|
317 | - $this->result->addOptions('ldap_loginfilter_attributes', $attributes); |
|
318 | - |
|
319 | - $selected = $this->configuration->ldapLoginFilterAttributes; |
|
320 | - if(is_array($selected) && !empty($selected)) { |
|
321 | - $this->result->addChange('ldap_loginfilter_attributes', $selected); |
|
322 | - } |
|
323 | - |
|
324 | - return $this->result; |
|
325 | - } |
|
326 | - |
|
327 | - /** |
|
328 | - * detects the available LDAP attributes |
|
329 | - * @return array|false The instance's WizardResult instance |
|
330 | - * @throws \Exception |
|
331 | - */ |
|
332 | - private function getUserAttributes() { |
|
333 | - if(!$this->checkRequirements(array('ldapHost', |
|
334 | - 'ldapPort', |
|
335 | - 'ldapBase', |
|
336 | - 'ldapUserFilter', |
|
337 | - ))) { |
|
338 | - return false; |
|
339 | - } |
|
340 | - $cr = $this->getConnection(); |
|
341 | - if(!$cr) { |
|
342 | - throw new \Exception('Could not connect to LDAP'); |
|
343 | - } |
|
344 | - |
|
345 | - $base = $this->configuration->ldapBase[0]; |
|
346 | - $filter = $this->configuration->ldapUserFilter; |
|
347 | - $rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1); |
|
348 | - if(!$this->ldap->isResource($rr)) { |
|
349 | - return false; |
|
350 | - } |
|
351 | - $er = $this->ldap->firstEntry($cr, $rr); |
|
352 | - $attributes = $this->ldap->getAttributes($cr, $er); |
|
353 | - $pureAttributes = array(); |
|
354 | - for($i = 0; $i < $attributes['count']; $i++) { |
|
355 | - $pureAttributes[] = $attributes[$i]; |
|
356 | - } |
|
357 | - |
|
358 | - return $pureAttributes; |
|
359 | - } |
|
360 | - |
|
361 | - /** |
|
362 | - * detects the available LDAP groups |
|
363 | - * @return WizardResult|false the instance's WizardResult instance |
|
364 | - */ |
|
365 | - public function determineGroupsForGroups() { |
|
366 | - return $this->determineGroups('ldap_groupfilter_groups', |
|
367 | - 'ldapGroupFilterGroups', |
|
368 | - false); |
|
369 | - } |
|
370 | - |
|
371 | - /** |
|
372 | - * detects the available LDAP groups |
|
373 | - * @return WizardResult|false the instance's WizardResult instance |
|
374 | - */ |
|
375 | - public function determineGroupsForUsers() { |
|
376 | - return $this->determineGroups('ldap_userfilter_groups', |
|
377 | - 'ldapUserFilterGroups'); |
|
378 | - } |
|
379 | - |
|
380 | - /** |
|
381 | - * detects the available LDAP groups |
|
382 | - * @param string $dbKey |
|
383 | - * @param string $confKey |
|
384 | - * @param bool $testMemberOf |
|
385 | - * @return WizardResult|false the instance's WizardResult instance |
|
386 | - * @throws \Exception |
|
387 | - */ |
|
388 | - private function determineGroups($dbKey, $confKey, $testMemberOf = true) { |
|
389 | - if(!$this->checkRequirements(array('ldapHost', |
|
390 | - 'ldapPort', |
|
391 | - 'ldapBase', |
|
392 | - ))) { |
|
393 | - return false; |
|
394 | - } |
|
395 | - $cr = $this->getConnection(); |
|
396 | - if(!$cr) { |
|
397 | - throw new \Exception('Could not connect to LDAP'); |
|
398 | - } |
|
399 | - |
|
400 | - $this->fetchGroups($dbKey, $confKey); |
|
401 | - |
|
402 | - if($testMemberOf) { |
|
403 | - $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); |
|
404 | - $this->result->markChange(); |
|
405 | - if(!$this->configuration->hasMemberOfFilterSupport) { |
|
406 | - throw new \Exception('memberOf is not supported by the server'); |
|
407 | - } |
|
408 | - } |
|
409 | - |
|
410 | - return $this->result; |
|
411 | - } |
|
412 | - |
|
413 | - /** |
|
414 | - * fetches all groups from LDAP and adds them to the result object |
|
415 | - * |
|
416 | - * @param string $dbKey |
|
417 | - * @param string $confKey |
|
418 | - * @return array $groupEntries |
|
419 | - * @throws \Exception |
|
420 | - */ |
|
421 | - public function fetchGroups($dbKey, $confKey) { |
|
422 | - $obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames'); |
|
423 | - |
|
424 | - $filterParts = array(); |
|
425 | - foreach($obclasses as $obclass) { |
|
426 | - $filterParts[] = 'objectclass='.$obclass; |
|
427 | - } |
|
428 | - //we filter for everything |
|
429 | - //- that looks like a group and |
|
430 | - //- has the group display name set |
|
431 | - $filter = $this->access->combineFilterWithOr($filterParts); |
|
432 | - $filter = $this->access->combineFilterWithAnd(array($filter, 'cn=*')); |
|
433 | - |
|
434 | - $groupNames = array(); |
|
435 | - $groupEntries = array(); |
|
436 | - $limit = 400; |
|
437 | - $offset = 0; |
|
438 | - do { |
|
439 | - // we need to request dn additionally here, otherwise memberOf |
|
440 | - // detection will fail later |
|
441 | - $result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset); |
|
442 | - foreach($result as $item) { |
|
443 | - if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) { |
|
444 | - // just in case - no issue known |
|
445 | - continue; |
|
446 | - } |
|
447 | - $groupNames[] = $item['cn'][0]; |
|
448 | - $groupEntries[] = $item; |
|
449 | - } |
|
450 | - $offset += $limit; |
|
451 | - } while ($this->access->hasMoreResults()); |
|
452 | - |
|
453 | - if(count($groupNames) > 0) { |
|
454 | - natsort($groupNames); |
|
455 | - $this->result->addOptions($dbKey, array_values($groupNames)); |
|
456 | - } else { |
|
457 | - throw new \Exception(self::$l->t('Could not find the desired feature')); |
|
458 | - } |
|
459 | - |
|
460 | - $setFeatures = $this->configuration->$confKey; |
|
461 | - if(is_array($setFeatures) && !empty($setFeatures)) { |
|
462 | - //something is already configured? pre-select it. |
|
463 | - $this->result->addChange($dbKey, $setFeatures); |
|
464 | - } |
|
465 | - return $groupEntries; |
|
466 | - } |
|
467 | - |
|
468 | - public function determineGroupMemberAssoc() { |
|
469 | - if(!$this->checkRequirements(array('ldapHost', |
|
470 | - 'ldapPort', |
|
471 | - 'ldapGroupFilter', |
|
472 | - ))) { |
|
473 | - return false; |
|
474 | - } |
|
475 | - $attribute = $this->detectGroupMemberAssoc(); |
|
476 | - if($attribute === false) { |
|
477 | - return false; |
|
478 | - } |
|
479 | - $this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute)); |
|
480 | - $this->result->addChange('ldap_group_member_assoc_attribute', $attribute); |
|
481 | - |
|
482 | - return $this->result; |
|
483 | - } |
|
484 | - |
|
485 | - /** |
|
486 | - * Detects the available object classes |
|
487 | - * @return WizardResult|false the instance's WizardResult instance |
|
488 | - * @throws \Exception |
|
489 | - */ |
|
490 | - public function determineGroupObjectClasses() { |
|
491 | - if(!$this->checkRequirements(array('ldapHost', |
|
492 | - 'ldapPort', |
|
493 | - 'ldapBase', |
|
494 | - ))) { |
|
495 | - return false; |
|
496 | - } |
|
497 | - $cr = $this->getConnection(); |
|
498 | - if(!$cr) { |
|
499 | - throw new \Exception('Could not connect to LDAP'); |
|
500 | - } |
|
501 | - |
|
502 | - $obclasses = array('groupOfNames', 'groupOfUniqueNames', 'group', 'posixGroup', '*'); |
|
503 | - $this->determineFeature($obclasses, |
|
504 | - 'objectclass', |
|
505 | - 'ldap_groupfilter_objectclass', |
|
506 | - 'ldapGroupFilterObjectclass', |
|
507 | - false); |
|
508 | - |
|
509 | - return $this->result; |
|
510 | - } |
|
511 | - |
|
512 | - /** |
|
513 | - * detects the available object classes |
|
514 | - * @return WizardResult |
|
515 | - * @throws \Exception |
|
516 | - */ |
|
517 | - public function determineUserObjectClasses() { |
|
518 | - if(!$this->checkRequirements(array('ldapHost', |
|
519 | - 'ldapPort', |
|
520 | - 'ldapBase', |
|
521 | - ))) { |
|
522 | - return false; |
|
523 | - } |
|
524 | - $cr = $this->getConnection(); |
|
525 | - if(!$cr) { |
|
526 | - throw new \Exception('Could not connect to LDAP'); |
|
527 | - } |
|
528 | - |
|
529 | - $obclasses = array('inetOrgPerson', 'person', 'organizationalPerson', |
|
530 | - 'user', 'posixAccount', '*'); |
|
531 | - $filter = $this->configuration->ldapUserFilter; |
|
532 | - //if filter is empty, it is probably the first time the wizard is called |
|
533 | - //then, apply suggestions. |
|
534 | - $this->determineFeature($obclasses, |
|
535 | - 'objectclass', |
|
536 | - 'ldap_userfilter_objectclass', |
|
537 | - 'ldapUserFilterObjectclass', |
|
538 | - empty($filter)); |
|
539 | - |
|
540 | - return $this->result; |
|
541 | - } |
|
542 | - |
|
543 | - /** |
|
544 | - * @return WizardResult|false |
|
545 | - * @throws \Exception |
|
546 | - */ |
|
547 | - public function getGroupFilter() { |
|
548 | - if(!$this->checkRequirements(array('ldapHost', |
|
549 | - 'ldapPort', |
|
550 | - 'ldapBase', |
|
551 | - ))) { |
|
552 | - return false; |
|
553 | - } |
|
554 | - //make sure the use display name is set |
|
555 | - $displayName = $this->configuration->ldapGroupDisplayName; |
|
556 | - if ($displayName === '') { |
|
557 | - $d = $this->configuration->getDefaults(); |
|
558 | - $this->applyFind('ldap_group_display_name', |
|
559 | - $d['ldap_group_display_name']); |
|
560 | - } |
|
561 | - $filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST); |
|
562 | - |
|
563 | - $this->applyFind('ldap_group_filter', $filter); |
|
564 | - return $this->result; |
|
565 | - } |
|
566 | - |
|
567 | - /** |
|
568 | - * @return WizardResult|false |
|
569 | - * @throws \Exception |
|
570 | - */ |
|
571 | - public function getUserListFilter() { |
|
572 | - if(!$this->checkRequirements(array('ldapHost', |
|
573 | - 'ldapPort', |
|
574 | - 'ldapBase', |
|
575 | - ))) { |
|
576 | - return false; |
|
577 | - } |
|
578 | - //make sure the use display name is set |
|
579 | - $displayName = $this->configuration->ldapUserDisplayName; |
|
580 | - if ($displayName === '') { |
|
581 | - $d = $this->configuration->getDefaults(); |
|
582 | - $this->applyFind('ldap_display_name', $d['ldap_display_name']); |
|
583 | - } |
|
584 | - $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST); |
|
585 | - if(!$filter) { |
|
586 | - throw new \Exception('Cannot create filter'); |
|
587 | - } |
|
588 | - |
|
589 | - $this->applyFind('ldap_userlist_filter', $filter); |
|
590 | - return $this->result; |
|
591 | - } |
|
592 | - |
|
593 | - /** |
|
594 | - * @return bool|WizardResult |
|
595 | - * @throws \Exception |
|
596 | - */ |
|
597 | - public function getUserLoginFilter() { |
|
598 | - if(!$this->checkRequirements(array('ldapHost', |
|
599 | - 'ldapPort', |
|
600 | - 'ldapBase', |
|
601 | - 'ldapUserFilter', |
|
602 | - ))) { |
|
603 | - return false; |
|
604 | - } |
|
605 | - |
|
606 | - $filter = $this->composeLdapFilter(self::LFILTER_LOGIN); |
|
607 | - if(!$filter) { |
|
608 | - throw new \Exception('Cannot create filter'); |
|
609 | - } |
|
610 | - |
|
611 | - $this->applyFind('ldap_login_filter', $filter); |
|
612 | - return $this->result; |
|
613 | - } |
|
614 | - |
|
615 | - /** |
|
616 | - * @return bool|WizardResult |
|
617 | - * @param string $loginName |
|
618 | - * @throws \Exception |
|
619 | - */ |
|
620 | - public function testLoginName($loginName) { |
|
621 | - if(!$this->checkRequirements(array('ldapHost', |
|
622 | - 'ldapPort', |
|
623 | - 'ldapBase', |
|
624 | - 'ldapLoginFilter', |
|
625 | - ))) { |
|
626 | - return false; |
|
627 | - } |
|
628 | - |
|
629 | - $cr = $this->access->connection->getConnectionResource(); |
|
630 | - if(!$this->ldap->isResource($cr)) { |
|
631 | - throw new \Exception('connection error'); |
|
632 | - } |
|
633 | - |
|
634 | - if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8') |
|
635 | - === false) { |
|
636 | - throw new \Exception('missing placeholder'); |
|
637 | - } |
|
638 | - |
|
639 | - $users = $this->access->countUsersByLoginName($loginName); |
|
640 | - if($this->ldap->errno($cr) !== 0) { |
|
641 | - throw new \Exception($this->ldap->error($cr)); |
|
642 | - } |
|
643 | - $filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter); |
|
644 | - $this->result->addChange('ldap_test_loginname', $users); |
|
645 | - $this->result->addChange('ldap_test_effective_filter', $filter); |
|
646 | - return $this->result; |
|
647 | - } |
|
648 | - |
|
649 | - /** |
|
650 | - * Tries to determine the port, requires given Host, User DN and Password |
|
651 | - * @return WizardResult|false WizardResult on success, false otherwise |
|
652 | - * @throws \Exception |
|
653 | - */ |
|
654 | - public function guessPortAndTLS() { |
|
655 | - if(!$this->checkRequirements(array('ldapHost', |
|
656 | - ))) { |
|
657 | - return false; |
|
658 | - } |
|
659 | - $this->checkHost(); |
|
660 | - $portSettings = $this->getPortSettingsToTry(); |
|
661 | - |
|
662 | - if(!is_array($portSettings)) { |
|
663 | - throw new \Exception(print_r($portSettings, true)); |
|
664 | - } |
|
665 | - |
|
666 | - //proceed from the best configuration and return on first success |
|
667 | - foreach($portSettings as $setting) { |
|
668 | - $p = $setting['port']; |
|
669 | - $t = $setting['tls']; |
|
670 | - \OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG); |
|
671 | - //connectAndBind may throw Exception, it needs to be catched by the |
|
672 | - //callee of this method |
|
673 | - |
|
674 | - try { |
|
675 | - $settingsFound = $this->connectAndBind($p, $t); |
|
676 | - } catch (\Exception $e) { |
|
677 | - // any reply other than -1 (= cannot connect) is already okay, |
|
678 | - // because then we found the server |
|
679 | - // unavailable startTLS returns -11 |
|
680 | - if($e->getCode() > 0) { |
|
681 | - $settingsFound = true; |
|
682 | - } else { |
|
683 | - throw $e; |
|
684 | - } |
|
685 | - } |
|
686 | - |
|
687 | - if ($settingsFound === true) { |
|
688 | - $config = array( |
|
689 | - 'ldapPort' => $p, |
|
690 | - 'ldapTLS' => intval($t) |
|
691 | - ); |
|
692 | - $this->configuration->setConfiguration($config); |
|
693 | - \OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG); |
|
694 | - $this->result->addChange('ldap_port', $p); |
|
695 | - return $this->result; |
|
696 | - } |
|
697 | - } |
|
698 | - |
|
699 | - //custom port, undetected (we do not brute force) |
|
700 | - return false; |
|
701 | - } |
|
702 | - |
|
703 | - /** |
|
704 | - * tries to determine a base dn from User DN or LDAP Host |
|
705 | - * @return WizardResult|false WizardResult on success, false otherwise |
|
706 | - */ |
|
707 | - public function guessBaseDN() { |
|
708 | - if(!$this->checkRequirements(array('ldapHost', |
|
709 | - 'ldapPort', |
|
710 | - ))) { |
|
711 | - return false; |
|
712 | - } |
|
713 | - |
|
714 | - //check whether a DN is given in the agent name (99.9% of all cases) |
|
715 | - $base = null; |
|
716 | - $i = stripos($this->configuration->ldapAgentName, 'dc='); |
|
717 | - if($i !== false) { |
|
718 | - $base = substr($this->configuration->ldapAgentName, $i); |
|
719 | - if($this->testBaseDN($base)) { |
|
720 | - $this->applyFind('ldap_base', $base); |
|
721 | - return $this->result; |
|
722 | - } |
|
723 | - } |
|
724 | - |
|
725 | - //this did not help :( |
|
726 | - //Let's see whether we can parse the Host URL and convert the domain to |
|
727 | - //a base DN |
|
728 | - $helper = new Helper(\OC::$server->getConfig()); |
|
729 | - $domain = $helper->getDomainFromURL($this->configuration->ldapHost); |
|
730 | - if(!$domain) { |
|
731 | - return false; |
|
732 | - } |
|
733 | - |
|
734 | - $dparts = explode('.', $domain); |
|
735 | - while(count($dparts) > 0) { |
|
736 | - $base2 = 'dc=' . implode(',dc=', $dparts); |
|
737 | - if ($base !== $base2 && $this->testBaseDN($base2)) { |
|
738 | - $this->applyFind('ldap_base', $base2); |
|
739 | - return $this->result; |
|
740 | - } |
|
741 | - array_shift($dparts); |
|
742 | - } |
|
743 | - |
|
744 | - return false; |
|
745 | - } |
|
746 | - |
|
747 | - /** |
|
748 | - * sets the found value for the configuration key in the WizardResult |
|
749 | - * as well as in the Configuration instance |
|
750 | - * @param string $key the configuration key |
|
751 | - * @param string $value the (detected) value |
|
752 | - * |
|
753 | - */ |
|
754 | - private function applyFind($key, $value) { |
|
755 | - $this->result->addChange($key, $value); |
|
756 | - $this->configuration->setConfiguration(array($key => $value)); |
|
757 | - } |
|
758 | - |
|
759 | - /** |
|
760 | - * Checks, whether a port was entered in the Host configuration |
|
761 | - * field. In this case the port will be stripped off, but also stored as |
|
762 | - * setting. |
|
763 | - */ |
|
764 | - private function checkHost() { |
|
765 | - $host = $this->configuration->ldapHost; |
|
766 | - $hostInfo = parse_url($host); |
|
767 | - |
|
768 | - //removes Port from Host |
|
769 | - if(is_array($hostInfo) && isset($hostInfo['port'])) { |
|
770 | - $port = $hostInfo['port']; |
|
771 | - $host = str_replace(':'.$port, '', $host); |
|
772 | - $this->applyFind('ldap_host', $host); |
|
773 | - $this->applyFind('ldap_port', $port); |
|
774 | - } |
|
775 | - } |
|
776 | - |
|
777 | - /** |
|
778 | - * tries to detect the group member association attribute which is |
|
779 | - * one of 'uniqueMember', 'memberUid', 'member', 'gidNumber' |
|
780 | - * @return string|false, string with the attribute name, false on error |
|
781 | - * @throws \Exception |
|
782 | - */ |
|
783 | - private function detectGroupMemberAssoc() { |
|
784 | - $possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'gidNumber'); |
|
785 | - $filter = $this->configuration->ldapGroupFilter; |
|
786 | - if(empty($filter)) { |
|
787 | - return false; |
|
788 | - } |
|
789 | - $cr = $this->getConnection(); |
|
790 | - if(!$cr) { |
|
791 | - throw new \Exception('Could not connect to LDAP'); |
|
792 | - } |
|
793 | - $base = $this->configuration->ldapBase[0]; |
|
794 | - $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000); |
|
795 | - if(!$this->ldap->isResource($rr)) { |
|
796 | - return false; |
|
797 | - } |
|
798 | - $er = $this->ldap->firstEntry($cr, $rr); |
|
799 | - while(is_resource($er)) { |
|
800 | - $this->ldap->getDN($cr, $er); |
|
801 | - $attrs = $this->ldap->getAttributes($cr, $er); |
|
802 | - $result = array(); |
|
803 | - $possibleAttrsCount = count($possibleAttrs); |
|
804 | - for($i = 0; $i < $possibleAttrsCount; $i++) { |
|
805 | - if(isset($attrs[$possibleAttrs[$i]])) { |
|
806 | - $result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count']; |
|
807 | - } |
|
808 | - } |
|
809 | - if(!empty($result)) { |
|
810 | - natsort($result); |
|
811 | - return key($result); |
|
812 | - } |
|
813 | - |
|
814 | - $er = $this->ldap->nextEntry($cr, $er); |
|
815 | - } |
|
816 | - |
|
817 | - return false; |
|
818 | - } |
|
819 | - |
|
820 | - /** |
|
821 | - * Checks whether for a given BaseDN results will be returned |
|
822 | - * @param string $base the BaseDN to test |
|
823 | - * @return bool true on success, false otherwise |
|
824 | - * @throws \Exception |
|
825 | - */ |
|
826 | - private function testBaseDN($base) { |
|
827 | - $cr = $this->getConnection(); |
|
828 | - if(!$cr) { |
|
829 | - throw new \Exception('Could not connect to LDAP'); |
|
830 | - } |
|
831 | - |
|
832 | - //base is there, let's validate it. If we search for anything, we should |
|
833 | - //get a result set > 0 on a proper base |
|
834 | - $rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1); |
|
835 | - if(!$this->ldap->isResource($rr)) { |
|
836 | - $errorNo = $this->ldap->errno($cr); |
|
837 | - $errorMsg = $this->ldap->error($cr); |
|
838 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base. |
|
839 | - ' Error '.$errorNo.': '.$errorMsg, \OCP\Util::INFO); |
|
840 | - return false; |
|
841 | - } |
|
842 | - $entries = $this->ldap->countEntries($cr, $rr); |
|
843 | - return ($entries !== false) && ($entries > 0); |
|
844 | - } |
|
845 | - |
|
846 | - /** |
|
847 | - * Checks whether the server supports memberOf in LDAP Filter. |
|
848 | - * Note: at least in OpenLDAP, availability of memberOf is dependent on |
|
849 | - * a configured objectClass. I.e. not necessarily for all available groups |
|
850 | - * memberOf does work. |
|
851 | - * |
|
852 | - * @return bool true if it does, false otherwise |
|
853 | - * @throws \Exception |
|
854 | - */ |
|
855 | - private function testMemberOf() { |
|
856 | - $cr = $this->getConnection(); |
|
857 | - if(!$cr) { |
|
858 | - throw new \Exception('Could not connect to LDAP'); |
|
859 | - } |
|
860 | - $result = $this->access->countUsers('memberOf=*', array('memberOf'), 1); |
|
861 | - if(is_int($result) && $result > 0) { |
|
862 | - return true; |
|
863 | - } |
|
864 | - return false; |
|
865 | - } |
|
866 | - |
|
867 | - /** |
|
868 | - * creates an LDAP Filter from given configuration |
|
869 | - * @param integer $filterType int, for which use case the filter shall be created |
|
870 | - * can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or |
|
871 | - * self::LFILTER_GROUP_LIST |
|
872 | - * @return string|false string with the filter on success, false otherwise |
|
873 | - * @throws \Exception |
|
874 | - */ |
|
875 | - private function composeLdapFilter($filterType) { |
|
876 | - $filter = ''; |
|
877 | - $parts = 0; |
|
878 | - switch ($filterType) { |
|
879 | - case self::LFILTER_USER_LIST: |
|
880 | - $objcs = $this->configuration->ldapUserFilterObjectclass; |
|
881 | - //glue objectclasses |
|
882 | - if(is_array($objcs) && count($objcs) > 0) { |
|
883 | - $filter .= '(|'; |
|
884 | - foreach($objcs as $objc) { |
|
885 | - $filter .= '(objectclass=' . $objc . ')'; |
|
886 | - } |
|
887 | - $filter .= ')'; |
|
888 | - $parts++; |
|
889 | - } |
|
890 | - //glue group memberships |
|
891 | - if($this->configuration->hasMemberOfFilterSupport) { |
|
892 | - $cns = $this->configuration->ldapUserFilterGroups; |
|
893 | - if(is_array($cns) && count($cns) > 0) { |
|
894 | - $filter .= '(|'; |
|
895 | - $cr = $this->getConnection(); |
|
896 | - if(!$cr) { |
|
897 | - throw new \Exception('Could not connect to LDAP'); |
|
898 | - } |
|
899 | - $base = $this->configuration->ldapBase[0]; |
|
900 | - foreach($cns as $cn) { |
|
901 | - $rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken')); |
|
902 | - if(!$this->ldap->isResource($rr)) { |
|
903 | - continue; |
|
904 | - } |
|
905 | - $er = $this->ldap->firstEntry($cr, $rr); |
|
906 | - $attrs = $this->ldap->getAttributes($cr, $er); |
|
907 | - $dn = $this->ldap->getDN($cr, $er); |
|
908 | - if ($dn == false || $dn === '') { |
|
909 | - continue; |
|
910 | - } |
|
911 | - $filterPart = '(memberof=' . $dn . ')'; |
|
912 | - if(isset($attrs['primaryGroupToken'])) { |
|
913 | - $pgt = $attrs['primaryGroupToken'][0]; |
|
914 | - $primaryFilterPart = '(primaryGroupID=' . $pgt .')'; |
|
915 | - $filterPart = '(|' . $filterPart . $primaryFilterPart . ')'; |
|
916 | - } |
|
917 | - $filter .= $filterPart; |
|
918 | - } |
|
919 | - $filter .= ')'; |
|
920 | - } |
|
921 | - $parts++; |
|
922 | - } |
|
923 | - //wrap parts in AND condition |
|
924 | - if($parts > 1) { |
|
925 | - $filter = '(&' . $filter . ')'; |
|
926 | - } |
|
927 | - if ($filter === '') { |
|
928 | - $filter = '(objectclass=*)'; |
|
929 | - } |
|
930 | - break; |
|
931 | - |
|
932 | - case self::LFILTER_GROUP_LIST: |
|
933 | - $objcs = $this->configuration->ldapGroupFilterObjectclass; |
|
934 | - //glue objectclasses |
|
935 | - if(is_array($objcs) && count($objcs) > 0) { |
|
936 | - $filter .= '(|'; |
|
937 | - foreach($objcs as $objc) { |
|
938 | - $filter .= '(objectclass=' . $objc . ')'; |
|
939 | - } |
|
940 | - $filter .= ')'; |
|
941 | - $parts++; |
|
942 | - } |
|
943 | - //glue group memberships |
|
944 | - $cns = $this->configuration->ldapGroupFilterGroups; |
|
945 | - if(is_array($cns) && count($cns) > 0) { |
|
946 | - $filter .= '(|'; |
|
947 | - foreach($cns as $cn) { |
|
948 | - $filter .= '(cn=' . $cn . ')'; |
|
949 | - } |
|
950 | - $filter .= ')'; |
|
951 | - } |
|
952 | - $parts++; |
|
953 | - //wrap parts in AND condition |
|
954 | - if($parts > 1) { |
|
955 | - $filter = '(&' . $filter . ')'; |
|
956 | - } |
|
957 | - break; |
|
958 | - |
|
959 | - case self::LFILTER_LOGIN: |
|
960 | - $ulf = $this->configuration->ldapUserFilter; |
|
961 | - $loginpart = '=%uid'; |
|
962 | - $filterUsername = ''; |
|
963 | - $userAttributes = $this->getUserAttributes(); |
|
964 | - $userAttributes = array_change_key_case(array_flip($userAttributes)); |
|
965 | - $parts = 0; |
|
966 | - |
|
967 | - if($this->configuration->ldapLoginFilterUsername === '1') { |
|
968 | - $attr = ''; |
|
969 | - if(isset($userAttributes['uid'])) { |
|
970 | - $attr = 'uid'; |
|
971 | - } else if(isset($userAttributes['samaccountname'])) { |
|
972 | - $attr = 'samaccountname'; |
|
973 | - } else if(isset($userAttributes['cn'])) { |
|
974 | - //fallback |
|
975 | - $attr = 'cn'; |
|
976 | - } |
|
977 | - if ($attr !== '') { |
|
978 | - $filterUsername = '(' . $attr . $loginpart . ')'; |
|
979 | - $parts++; |
|
980 | - } |
|
981 | - } |
|
982 | - |
|
983 | - $filterEmail = ''; |
|
984 | - if($this->configuration->ldapLoginFilterEmail === '1') { |
|
985 | - $filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))'; |
|
986 | - $parts++; |
|
987 | - } |
|
988 | - |
|
989 | - $filterAttributes = ''; |
|
990 | - $attrsToFilter = $this->configuration->ldapLoginFilterAttributes; |
|
991 | - if(is_array($attrsToFilter) && count($attrsToFilter) > 0) { |
|
992 | - $filterAttributes = '(|'; |
|
993 | - foreach($attrsToFilter as $attribute) { |
|
994 | - $filterAttributes .= '(' . $attribute . $loginpart . ')'; |
|
995 | - } |
|
996 | - $filterAttributes .= ')'; |
|
997 | - $parts++; |
|
998 | - } |
|
999 | - |
|
1000 | - $filterLogin = ''; |
|
1001 | - if($parts > 1) { |
|
1002 | - $filterLogin = '(|'; |
|
1003 | - } |
|
1004 | - $filterLogin .= $filterUsername; |
|
1005 | - $filterLogin .= $filterEmail; |
|
1006 | - $filterLogin .= $filterAttributes; |
|
1007 | - if($parts > 1) { |
|
1008 | - $filterLogin .= ')'; |
|
1009 | - } |
|
1010 | - |
|
1011 | - $filter = '(&'.$ulf.$filterLogin.')'; |
|
1012 | - break; |
|
1013 | - } |
|
1014 | - |
|
1015 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG); |
|
1016 | - |
|
1017 | - return $filter; |
|
1018 | - } |
|
1019 | - |
|
1020 | - /** |
|
1021 | - * Connects and Binds to an LDAP Server |
|
1022 | - * @param int $port the port to connect with |
|
1023 | - * @param bool $tls whether startTLS is to be used |
|
1024 | - * @param bool $ncc |
|
1025 | - * @return bool |
|
1026 | - * @throws \Exception |
|
1027 | - */ |
|
1028 | - private function connectAndBind($port = 389, $tls = false, $ncc = false) { |
|
1029 | - if($ncc) { |
|
1030 | - //No certificate check |
|
1031 | - //FIXME: undo afterwards |
|
1032 | - putenv('LDAPTLS_REQCERT=never'); |
|
1033 | - } |
|
1034 | - |
|
1035 | - //connect, does not really trigger any server communication |
|
1036 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Checking Host Info ', \OCP\Util::DEBUG); |
|
1037 | - $host = $this->configuration->ldapHost; |
|
1038 | - $hostInfo = parse_url($host); |
|
1039 | - if(!$hostInfo) { |
|
1040 | - throw new \Exception(self::$l->t('Invalid Host')); |
|
1041 | - } |
|
1042 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG); |
|
1043 | - $cr = $this->ldap->connect($host, $port); |
|
1044 | - if(!is_resource($cr)) { |
|
1045 | - throw new \Exception(self::$l->t('Invalid Host')); |
|
1046 | - } |
|
1047 | - |
|
1048 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Setting LDAP Options ', \OCP\Util::DEBUG); |
|
1049 | - //set LDAP options |
|
1050 | - $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); |
|
1051 | - $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0); |
|
1052 | - $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); |
|
1053 | - |
|
1054 | - try { |
|
1055 | - if($tls) { |
|
1056 | - $isTlsWorking = @$this->ldap->startTls($cr); |
|
1057 | - if(!$isTlsWorking) { |
|
1058 | - return false; |
|
1059 | - } |
|
1060 | - } |
|
1061 | - |
|
1062 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG); |
|
1063 | - //interesting part: do the bind! |
|
1064 | - $login = $this->ldap->bind($cr, |
|
1065 | - $this->configuration->ldapAgentName, |
|
1066 | - $this->configuration->ldapAgentPassword |
|
1067 | - ); |
|
1068 | - $errNo = $this->ldap->errno($cr); |
|
1069 | - $error = ldap_error($cr); |
|
1070 | - $this->ldap->unbind($cr); |
|
1071 | - } catch(ServerNotAvailableException $e) { |
|
1072 | - return false; |
|
1073 | - } |
|
1074 | - |
|
1075 | - if($login === true) { |
|
1076 | - $this->ldap->unbind($cr); |
|
1077 | - if($ncc) { |
|
1078 | - throw new \Exception('Certificate cannot be validated.'); |
|
1079 | - } |
|
1080 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . intval($tls), \OCP\Util::DEBUG); |
|
1081 | - return true; |
|
1082 | - } |
|
1083 | - |
|
1084 | - if($errNo === -1 || ($errNo === 2 && $ncc)) { |
|
1085 | - //host, port or TLS wrong |
|
1086 | - return false; |
|
1087 | - } else if ($errNo === 2) { |
|
1088 | - return $this->connectAndBind($port, $tls, true); |
|
1089 | - } |
|
1090 | - throw new \Exception($error, $errNo); |
|
1091 | - } |
|
1092 | - |
|
1093 | - /** |
|
1094 | - * checks whether a valid combination of agent and password has been |
|
1095 | - * provided (either two values or nothing for anonymous connect) |
|
1096 | - * @return bool, true if everything is fine, false otherwise |
|
1097 | - */ |
|
1098 | - private function checkAgentRequirements() { |
|
1099 | - $agent = $this->configuration->ldapAgentName; |
|
1100 | - $pwd = $this->configuration->ldapAgentPassword; |
|
1101 | - |
|
1102 | - return |
|
1103 | - ($agent !== '' && $pwd !== '') |
|
1104 | - || ($agent === '' && $pwd === '') |
|
1105 | - ; |
|
1106 | - } |
|
1107 | - |
|
1108 | - /** |
|
1109 | - * @param array $reqs |
|
1110 | - * @return bool |
|
1111 | - */ |
|
1112 | - private function checkRequirements($reqs) { |
|
1113 | - $this->checkAgentRequirements(); |
|
1114 | - foreach($reqs as $option) { |
|
1115 | - $value = $this->configuration->$option; |
|
1116 | - if(empty($value)) { |
|
1117 | - return false; |
|
1118 | - } |
|
1119 | - } |
|
1120 | - return true; |
|
1121 | - } |
|
1122 | - |
|
1123 | - /** |
|
1124 | - * does a cumulativeSearch on LDAP to get different values of a |
|
1125 | - * specified attribute |
|
1126 | - * @param string[] $filters array, the filters that shall be used in the search |
|
1127 | - * @param string $attr the attribute of which a list of values shall be returned |
|
1128 | - * @param int $dnReadLimit the amount of how many DNs should be analyzed. |
|
1129 | - * The lower, the faster |
|
1130 | - * @param string $maxF string. if not null, this variable will have the filter that |
|
1131 | - * yields most result entries |
|
1132 | - * @return array|false an array with the values on success, false otherwise |
|
1133 | - */ |
|
1134 | - public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) { |
|
1135 | - $dnRead = array(); |
|
1136 | - $foundItems = array(); |
|
1137 | - $maxEntries = 0; |
|
1138 | - if(!is_array($this->configuration->ldapBase) |
|
1139 | - || !isset($this->configuration->ldapBase[0])) { |
|
1140 | - return false; |
|
1141 | - } |
|
1142 | - $base = $this->configuration->ldapBase[0]; |
|
1143 | - $cr = $this->getConnection(); |
|
1144 | - if(!$this->ldap->isResource($cr)) { |
|
1145 | - return false; |
|
1146 | - } |
|
1147 | - $lastFilter = null; |
|
1148 | - if(isset($filters[count($filters)-1])) { |
|
1149 | - $lastFilter = $filters[count($filters)-1]; |
|
1150 | - } |
|
1151 | - foreach($filters as $filter) { |
|
1152 | - if($lastFilter === $filter && count($foundItems) > 0) { |
|
1153 | - //skip when the filter is a wildcard and results were found |
|
1154 | - continue; |
|
1155 | - } |
|
1156 | - // 20k limit for performance and reason |
|
1157 | - $rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000); |
|
1158 | - if(!$this->ldap->isResource($rr)) { |
|
1159 | - continue; |
|
1160 | - } |
|
1161 | - $entries = $this->ldap->countEntries($cr, $rr); |
|
1162 | - $getEntryFunc = 'firstEntry'; |
|
1163 | - if(($entries !== false) && ($entries > 0)) { |
|
1164 | - if(!is_null($maxF) && $entries > $maxEntries) { |
|
1165 | - $maxEntries = $entries; |
|
1166 | - $maxF = $filter; |
|
1167 | - } |
|
1168 | - $dnReadCount = 0; |
|
1169 | - do { |
|
1170 | - $entry = $this->ldap->$getEntryFunc($cr, $rr); |
|
1171 | - $getEntryFunc = 'nextEntry'; |
|
1172 | - if(!$this->ldap->isResource($entry)) { |
|
1173 | - continue 2; |
|
1174 | - } |
|
1175 | - $rr = $entry; //will be expected by nextEntry next round |
|
1176 | - $attributes = $this->ldap->getAttributes($cr, $entry); |
|
1177 | - $dn = $this->ldap->getDN($cr, $entry); |
|
1178 | - if($dn === false || in_array($dn, $dnRead)) { |
|
1179 | - continue; |
|
1180 | - } |
|
1181 | - $newItems = array(); |
|
1182 | - $state = $this->getAttributeValuesFromEntry($attributes, |
|
1183 | - $attr, |
|
1184 | - $newItems); |
|
1185 | - $dnReadCount++; |
|
1186 | - $foundItems = array_merge($foundItems, $newItems); |
|
1187 | - $this->resultCache[$dn][$attr] = $newItems; |
|
1188 | - $dnRead[] = $dn; |
|
1189 | - } while(($state === self::LRESULT_PROCESSED_SKIP |
|
1190 | - || $this->ldap->isResource($entry)) |
|
1191 | - && ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit)); |
|
1192 | - } |
|
1193 | - } |
|
1194 | - |
|
1195 | - return array_unique($foundItems); |
|
1196 | - } |
|
1197 | - |
|
1198 | - /** |
|
1199 | - * determines if and which $attr are available on the LDAP server |
|
1200 | - * @param string[] $objectclasses the objectclasses to use as search filter |
|
1201 | - * @param string $attr the attribute to look for |
|
1202 | - * @param string $dbkey the dbkey of the setting the feature is connected to |
|
1203 | - * @param string $confkey the confkey counterpart for the $dbkey as used in the |
|
1204 | - * Configuration class |
|
1205 | - * @param bool $po whether the objectClass with most result entries |
|
1206 | - * shall be pre-selected via the result |
|
1207 | - * @return array|false list of found items. |
|
1208 | - * @throws \Exception |
|
1209 | - */ |
|
1210 | - private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) { |
|
1211 | - $cr = $this->getConnection(); |
|
1212 | - if(!$cr) { |
|
1213 | - throw new \Exception('Could not connect to LDAP'); |
|
1214 | - } |
|
1215 | - $p = 'objectclass='; |
|
1216 | - foreach($objectclasses as $key => $value) { |
|
1217 | - $objectclasses[$key] = $p.$value; |
|
1218 | - } |
|
1219 | - $maxEntryObjC = ''; |
|
1220 | - |
|
1221 | - //how deep to dig? |
|
1222 | - //When looking for objectclasses, testing few entries is sufficient, |
|
1223 | - $dig = 3; |
|
1224 | - |
|
1225 | - $availableFeatures = |
|
1226 | - $this->cumulativeSearchOnAttribute($objectclasses, $attr, |
|
1227 | - $dig, $maxEntryObjC); |
|
1228 | - if(is_array($availableFeatures) |
|
1229 | - && count($availableFeatures) > 0) { |
|
1230 | - natcasesort($availableFeatures); |
|
1231 | - //natcasesort keeps indices, but we must get rid of them for proper |
|
1232 | - //sorting in the web UI. Therefore: array_values |
|
1233 | - $this->result->addOptions($dbkey, array_values($availableFeatures)); |
|
1234 | - } else { |
|
1235 | - throw new \Exception(self::$l->t('Could not find the desired feature')); |
|
1236 | - } |
|
1237 | - |
|
1238 | - $setFeatures = $this->configuration->$confkey; |
|
1239 | - if(is_array($setFeatures) && !empty($setFeatures)) { |
|
1240 | - //something is already configured? pre-select it. |
|
1241 | - $this->result->addChange($dbkey, $setFeatures); |
|
1242 | - } else if ($po && $maxEntryObjC !== '') { |
|
1243 | - //pre-select objectclass with most result entries |
|
1244 | - $maxEntryObjC = str_replace($p, '', $maxEntryObjC); |
|
1245 | - $this->applyFind($dbkey, $maxEntryObjC); |
|
1246 | - $this->result->addChange($dbkey, $maxEntryObjC); |
|
1247 | - } |
|
1248 | - |
|
1249 | - return $availableFeatures; |
|
1250 | - } |
|
1251 | - |
|
1252 | - /** |
|
1253 | - * appends a list of values fr |
|
1254 | - * @param resource $result the return value from ldap_get_attributes |
|
1255 | - * @param string $attribute the attribute values to look for |
|
1256 | - * @param array &$known new values will be appended here |
|
1257 | - * @return int, state on of the class constants LRESULT_PROCESSED_OK, |
|
1258 | - * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP |
|
1259 | - */ |
|
1260 | - private function getAttributeValuesFromEntry($result, $attribute, &$known) { |
|
1261 | - if(!is_array($result) |
|
1262 | - || !isset($result['count']) |
|
1263 | - || !$result['count'] > 0) { |
|
1264 | - return self::LRESULT_PROCESSED_INVALID; |
|
1265 | - } |
|
1266 | - |
|
1267 | - // strtolower on all keys for proper comparison |
|
1268 | - $result = \OCP\Util::mb_array_change_key_case($result); |
|
1269 | - $attribute = strtolower($attribute); |
|
1270 | - if(isset($result[$attribute])) { |
|
1271 | - foreach($result[$attribute] as $key => $val) { |
|
1272 | - if($key === 'count') { |
|
1273 | - continue; |
|
1274 | - } |
|
1275 | - if(!in_array($val, $known)) { |
|
1276 | - $known[] = $val; |
|
1277 | - } |
|
1278 | - } |
|
1279 | - return self::LRESULT_PROCESSED_OK; |
|
1280 | - } else { |
|
1281 | - return self::LRESULT_PROCESSED_SKIP; |
|
1282 | - } |
|
1283 | - } |
|
1284 | - |
|
1285 | - /** |
|
1286 | - * @return bool|mixed |
|
1287 | - */ |
|
1288 | - private function getConnection() { |
|
1289 | - if(!is_null($this->cr)) { |
|
1290 | - return $this->cr; |
|
1291 | - } |
|
1292 | - |
|
1293 | - $cr = $this->ldap->connect( |
|
1294 | - $this->configuration->ldapHost, |
|
1295 | - $this->configuration->ldapPort |
|
1296 | - ); |
|
1297 | - |
|
1298 | - $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); |
|
1299 | - $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0); |
|
1300 | - $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); |
|
1301 | - if($this->configuration->ldapTLS === 1) { |
|
1302 | - $this->ldap->startTls($cr); |
|
1303 | - } |
|
1304 | - |
|
1305 | - $lo = @$this->ldap->bind($cr, |
|
1306 | - $this->configuration->ldapAgentName, |
|
1307 | - $this->configuration->ldapAgentPassword); |
|
1308 | - if($lo === true) { |
|
1309 | - $this->$cr = $cr; |
|
1310 | - return $cr; |
|
1311 | - } |
|
1312 | - |
|
1313 | - return false; |
|
1314 | - } |
|
1315 | - |
|
1316 | - /** |
|
1317 | - * @return array |
|
1318 | - */ |
|
1319 | - private function getDefaultLdapPortSettings() { |
|
1320 | - static $settings = array( |
|
1321 | - array('port' => 7636, 'tls' => false), |
|
1322 | - array('port' => 636, 'tls' => false), |
|
1323 | - array('port' => 7389, 'tls' => true), |
|
1324 | - array('port' => 389, 'tls' => true), |
|
1325 | - array('port' => 7389, 'tls' => false), |
|
1326 | - array('port' => 389, 'tls' => false), |
|
1327 | - ); |
|
1328 | - return $settings; |
|
1329 | - } |
|
1330 | - |
|
1331 | - /** |
|
1332 | - * @return array |
|
1333 | - */ |
|
1334 | - private function getPortSettingsToTry() { |
|
1335 | - //389 ← LDAP / Unencrypted or StartTLS |
|
1336 | - //636 ← LDAPS / SSL |
|
1337 | - //7xxx ← UCS. need to be checked first, because both ports may be open |
|
1338 | - $host = $this->configuration->ldapHost; |
|
1339 | - $port = intval($this->configuration->ldapPort); |
|
1340 | - $portSettings = array(); |
|
1341 | - |
|
1342 | - //In case the port is already provided, we will check this first |
|
1343 | - if($port > 0) { |
|
1344 | - $hostInfo = parse_url($host); |
|
1345 | - if(!(is_array($hostInfo) |
|
1346 | - && isset($hostInfo['scheme']) |
|
1347 | - && stripos($hostInfo['scheme'], 'ldaps') !== false)) { |
|
1348 | - $portSettings[] = array('port' => $port, 'tls' => true); |
|
1349 | - } |
|
1350 | - $portSettings[] =array('port' => $port, 'tls' => false); |
|
1351 | - } |
|
1352 | - |
|
1353 | - //default ports |
|
1354 | - $portSettings = array_merge($portSettings, |
|
1355 | - $this->getDefaultLdapPortSettings()); |
|
1356 | - |
|
1357 | - return $portSettings; |
|
1358 | - } |
|
41 | + /** @var \OCP\IL10N */ |
|
42 | + static protected $l; |
|
43 | + protected $access; |
|
44 | + protected $cr; |
|
45 | + protected $configuration; |
|
46 | + protected $result; |
|
47 | + protected $resultCache = array(); |
|
48 | + |
|
49 | + const LRESULT_PROCESSED_OK = 2; |
|
50 | + const LRESULT_PROCESSED_INVALID = 3; |
|
51 | + const LRESULT_PROCESSED_SKIP = 4; |
|
52 | + |
|
53 | + const LFILTER_LOGIN = 2; |
|
54 | + const LFILTER_USER_LIST = 3; |
|
55 | + const LFILTER_GROUP_LIST = 4; |
|
56 | + |
|
57 | + const LFILTER_MODE_ASSISTED = 2; |
|
58 | + const LFILTER_MODE_RAW = 1; |
|
59 | + |
|
60 | + const LDAP_NW_TIMEOUT = 4; |
|
61 | + |
|
62 | + /** |
|
63 | + * Constructor |
|
64 | + * @param Configuration $configuration an instance of Configuration |
|
65 | + * @param ILDAPWrapper $ldap an instance of ILDAPWrapper |
|
66 | + * @param Access $access |
|
67 | + */ |
|
68 | + public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) { |
|
69 | + parent::__construct($ldap); |
|
70 | + $this->configuration = $configuration; |
|
71 | + if(is_null(Wizard::$l)) { |
|
72 | + Wizard::$l = \OC::$server->getL10N('user_ldap'); |
|
73 | + } |
|
74 | + $this->access = $access; |
|
75 | + $this->result = new WizardResult(); |
|
76 | + } |
|
77 | + |
|
78 | + public function __destruct() { |
|
79 | + if($this->result->hasChanges()) { |
|
80 | + $this->configuration->saveConfiguration(); |
|
81 | + } |
|
82 | + } |
|
83 | + |
|
84 | + /** |
|
85 | + * counts entries in the LDAP directory |
|
86 | + * |
|
87 | + * @param string $filter the LDAP search filter |
|
88 | + * @param string $type a string being either 'users' or 'groups'; |
|
89 | + * @return bool|int |
|
90 | + * @throws \Exception |
|
91 | + */ |
|
92 | + public function countEntries($filter, $type) { |
|
93 | + $reqs = array('ldapHost', 'ldapPort', 'ldapBase'); |
|
94 | + if($type === 'users') { |
|
95 | + $reqs[] = 'ldapUserFilter'; |
|
96 | + } |
|
97 | + if(!$this->checkRequirements($reqs)) { |
|
98 | + throw new \Exception('Requirements not met', 400); |
|
99 | + } |
|
100 | + |
|
101 | + $attr = array('dn'); // default |
|
102 | + $limit = 1001; |
|
103 | + if($type === 'groups') { |
|
104 | + $result = $this->access->countGroups($filter, $attr, $limit); |
|
105 | + } else if($type === 'users') { |
|
106 | + $result = $this->access->countUsers($filter, $attr, $limit); |
|
107 | + } else if ($type === 'objects') { |
|
108 | + $result = $this->access->countObjects($limit); |
|
109 | + } else { |
|
110 | + throw new \Exception('internal error: invalid object type', 500); |
|
111 | + } |
|
112 | + |
|
113 | + return $result; |
|
114 | + } |
|
115 | + |
|
116 | + /** |
|
117 | + * formats the return value of a count operation to the string to be |
|
118 | + * inserted. |
|
119 | + * |
|
120 | + * @param bool|int $count |
|
121 | + * @return int|string |
|
122 | + */ |
|
123 | + private function formatCountResult($count) { |
|
124 | + $formatted = ($count !== false) ? $count : 0; |
|
125 | + if($formatted > 1000) { |
|
126 | + $formatted = '> 1000'; |
|
127 | + } |
|
128 | + return $formatted; |
|
129 | + } |
|
130 | + |
|
131 | + public function countGroups() { |
|
132 | + $filter = $this->configuration->ldapGroupFilter; |
|
133 | + |
|
134 | + if(empty($filter)) { |
|
135 | + $output = self::$l->n('%s group found', '%s groups found', 0, array(0)); |
|
136 | + $this->result->addChange('ldap_group_count', $output); |
|
137 | + return $this->result; |
|
138 | + } |
|
139 | + |
|
140 | + try { |
|
141 | + $groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups')); |
|
142 | + } catch (\Exception $e) { |
|
143 | + //400 can be ignored, 500 is forwarded |
|
144 | + if($e->getCode() === 500) { |
|
145 | + throw $e; |
|
146 | + } |
|
147 | + return false; |
|
148 | + } |
|
149 | + $output = self::$l->n('%s group found', '%s groups found', $groupsTotal, array($groupsTotal)); |
|
150 | + $this->result->addChange('ldap_group_count', $output); |
|
151 | + return $this->result; |
|
152 | + } |
|
153 | + |
|
154 | + /** |
|
155 | + * @return WizardResult |
|
156 | + * @throws \Exception |
|
157 | + */ |
|
158 | + public function countUsers() { |
|
159 | + $filter = $this->access->getFilterForUserCount(); |
|
160 | + |
|
161 | + $usersTotal = $this->formatCountResult($this->countEntries($filter, 'users')); |
|
162 | + $output = self::$l->n('%s user found', '%s users found', $usersTotal, array($usersTotal)); |
|
163 | + $this->result->addChange('ldap_user_count', $output); |
|
164 | + return $this->result; |
|
165 | + } |
|
166 | + |
|
167 | + /** |
|
168 | + * counts any objects in the currently set base dn |
|
169 | + * |
|
170 | + * @return WizardResult |
|
171 | + * @throws \Exception |
|
172 | + */ |
|
173 | + public function countInBaseDN() { |
|
174 | + // we don't need to provide a filter in this case |
|
175 | + $total = $this->countEntries(null, 'objects'); |
|
176 | + if($total === false) { |
|
177 | + throw new \Exception('invalid results received'); |
|
178 | + } |
|
179 | + $this->result->addChange('ldap_test_base', $total); |
|
180 | + return $this->result; |
|
181 | + } |
|
182 | + |
|
183 | + /** |
|
184 | + * counts users with a specified attribute |
|
185 | + * @param string $attr |
|
186 | + * @param bool $existsCheck |
|
187 | + * @return int|bool |
|
188 | + */ |
|
189 | + public function countUsersWithAttribute($attr, $existsCheck = false) { |
|
190 | + if(!$this->checkRequirements(array('ldapHost', |
|
191 | + 'ldapPort', |
|
192 | + 'ldapBase', |
|
193 | + 'ldapUserFilter', |
|
194 | + ))) { |
|
195 | + return false; |
|
196 | + } |
|
197 | + |
|
198 | + $filter = $this->access->combineFilterWithAnd(array( |
|
199 | + $this->configuration->ldapUserFilter, |
|
200 | + $attr . '=*' |
|
201 | + )); |
|
202 | + |
|
203 | + $limit = ($existsCheck === false) ? null : 1; |
|
204 | + |
|
205 | + return $this->access->countUsers($filter, array('dn'), $limit); |
|
206 | + } |
|
207 | + |
|
208 | + /** |
|
209 | + * detects the display name attribute. If a setting is already present that |
|
210 | + * returns at least one hit, the detection will be canceled. |
|
211 | + * @return WizardResult|bool |
|
212 | + * @throws \Exception |
|
213 | + */ |
|
214 | + public function detectUserDisplayNameAttribute() { |
|
215 | + if(!$this->checkRequirements(array('ldapHost', |
|
216 | + 'ldapPort', |
|
217 | + 'ldapBase', |
|
218 | + 'ldapUserFilter', |
|
219 | + ))) { |
|
220 | + return false; |
|
221 | + } |
|
222 | + |
|
223 | + $attr = $this->configuration->ldapUserDisplayName; |
|
224 | + if ($attr !== '' && $attr !== 'displayName') { |
|
225 | + // most likely not the default value with upper case N, |
|
226 | + // verify it still produces a result |
|
227 | + $count = intval($this->countUsersWithAttribute($attr, true)); |
|
228 | + if($count > 0) { |
|
229 | + //no change, but we sent it back to make sure the user interface |
|
230 | + //is still correct, even if the ajax call was cancelled meanwhile |
|
231 | + $this->result->addChange('ldap_display_name', $attr); |
|
232 | + return $this->result; |
|
233 | + } |
|
234 | + } |
|
235 | + |
|
236 | + // first attribute that has at least one result wins |
|
237 | + $displayNameAttrs = array('displayname', 'cn'); |
|
238 | + foreach ($displayNameAttrs as $attr) { |
|
239 | + $count = intval($this->countUsersWithAttribute($attr, true)); |
|
240 | + |
|
241 | + if($count > 0) { |
|
242 | + $this->applyFind('ldap_display_name', $attr); |
|
243 | + return $this->result; |
|
244 | + } |
|
245 | + }; |
|
246 | + |
|
247 | + throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced ldap settings.')); |
|
248 | + } |
|
249 | + |
|
250 | + /** |
|
251 | + * detects the most often used email attribute for users applying to the |
|
252 | + * user list filter. If a setting is already present that returns at least |
|
253 | + * one hit, the detection will be canceled. |
|
254 | + * @return WizardResult|bool |
|
255 | + */ |
|
256 | + public function detectEmailAttribute() { |
|
257 | + if(!$this->checkRequirements(array('ldapHost', |
|
258 | + 'ldapPort', |
|
259 | + 'ldapBase', |
|
260 | + 'ldapUserFilter', |
|
261 | + ))) { |
|
262 | + return false; |
|
263 | + } |
|
264 | + |
|
265 | + $attr = $this->configuration->ldapEmailAttribute; |
|
266 | + if ($attr !== '') { |
|
267 | + $count = intval($this->countUsersWithAttribute($attr, true)); |
|
268 | + if($count > 0) { |
|
269 | + return false; |
|
270 | + } |
|
271 | + $writeLog = true; |
|
272 | + } else { |
|
273 | + $writeLog = false; |
|
274 | + } |
|
275 | + |
|
276 | + $emailAttributes = array('mail', 'mailPrimaryAddress'); |
|
277 | + $winner = ''; |
|
278 | + $maxUsers = 0; |
|
279 | + foreach($emailAttributes as $attr) { |
|
280 | + $count = $this->countUsersWithAttribute($attr); |
|
281 | + if($count > $maxUsers) { |
|
282 | + $maxUsers = $count; |
|
283 | + $winner = $attr; |
|
284 | + } |
|
285 | + } |
|
286 | + |
|
287 | + if($winner !== '') { |
|
288 | + $this->applyFind('ldap_email_attr', $winner); |
|
289 | + if($writeLog) { |
|
290 | + \OCP\Util::writeLog('user_ldap', 'The mail attribute has ' . |
|
291 | + 'automatically been reset, because the original value ' . |
|
292 | + 'did not return any results.', \OCP\Util::INFO); |
|
293 | + } |
|
294 | + } |
|
295 | + |
|
296 | + return $this->result; |
|
297 | + } |
|
298 | + |
|
299 | + /** |
|
300 | + * @return WizardResult |
|
301 | + * @throws \Exception |
|
302 | + */ |
|
303 | + public function determineAttributes() { |
|
304 | + if(!$this->checkRequirements(array('ldapHost', |
|
305 | + 'ldapPort', |
|
306 | + 'ldapBase', |
|
307 | + 'ldapUserFilter', |
|
308 | + ))) { |
|
309 | + return false; |
|
310 | + } |
|
311 | + |
|
312 | + $attributes = $this->getUserAttributes(); |
|
313 | + |
|
314 | + natcasesort($attributes); |
|
315 | + $attributes = array_values($attributes); |
|
316 | + |
|
317 | + $this->result->addOptions('ldap_loginfilter_attributes', $attributes); |
|
318 | + |
|
319 | + $selected = $this->configuration->ldapLoginFilterAttributes; |
|
320 | + if(is_array($selected) && !empty($selected)) { |
|
321 | + $this->result->addChange('ldap_loginfilter_attributes', $selected); |
|
322 | + } |
|
323 | + |
|
324 | + return $this->result; |
|
325 | + } |
|
326 | + |
|
327 | + /** |
|
328 | + * detects the available LDAP attributes |
|
329 | + * @return array|false The instance's WizardResult instance |
|
330 | + * @throws \Exception |
|
331 | + */ |
|
332 | + private function getUserAttributes() { |
|
333 | + if(!$this->checkRequirements(array('ldapHost', |
|
334 | + 'ldapPort', |
|
335 | + 'ldapBase', |
|
336 | + 'ldapUserFilter', |
|
337 | + ))) { |
|
338 | + return false; |
|
339 | + } |
|
340 | + $cr = $this->getConnection(); |
|
341 | + if(!$cr) { |
|
342 | + throw new \Exception('Could not connect to LDAP'); |
|
343 | + } |
|
344 | + |
|
345 | + $base = $this->configuration->ldapBase[0]; |
|
346 | + $filter = $this->configuration->ldapUserFilter; |
|
347 | + $rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1); |
|
348 | + if(!$this->ldap->isResource($rr)) { |
|
349 | + return false; |
|
350 | + } |
|
351 | + $er = $this->ldap->firstEntry($cr, $rr); |
|
352 | + $attributes = $this->ldap->getAttributes($cr, $er); |
|
353 | + $pureAttributes = array(); |
|
354 | + for($i = 0; $i < $attributes['count']; $i++) { |
|
355 | + $pureAttributes[] = $attributes[$i]; |
|
356 | + } |
|
357 | + |
|
358 | + return $pureAttributes; |
|
359 | + } |
|
360 | + |
|
361 | + /** |
|
362 | + * detects the available LDAP groups |
|
363 | + * @return WizardResult|false the instance's WizardResult instance |
|
364 | + */ |
|
365 | + public function determineGroupsForGroups() { |
|
366 | + return $this->determineGroups('ldap_groupfilter_groups', |
|
367 | + 'ldapGroupFilterGroups', |
|
368 | + false); |
|
369 | + } |
|
370 | + |
|
371 | + /** |
|
372 | + * detects the available LDAP groups |
|
373 | + * @return WizardResult|false the instance's WizardResult instance |
|
374 | + */ |
|
375 | + public function determineGroupsForUsers() { |
|
376 | + return $this->determineGroups('ldap_userfilter_groups', |
|
377 | + 'ldapUserFilterGroups'); |
|
378 | + } |
|
379 | + |
|
380 | + /** |
|
381 | + * detects the available LDAP groups |
|
382 | + * @param string $dbKey |
|
383 | + * @param string $confKey |
|
384 | + * @param bool $testMemberOf |
|
385 | + * @return WizardResult|false the instance's WizardResult instance |
|
386 | + * @throws \Exception |
|
387 | + */ |
|
388 | + private function determineGroups($dbKey, $confKey, $testMemberOf = true) { |
|
389 | + if(!$this->checkRequirements(array('ldapHost', |
|
390 | + 'ldapPort', |
|
391 | + 'ldapBase', |
|
392 | + ))) { |
|
393 | + return false; |
|
394 | + } |
|
395 | + $cr = $this->getConnection(); |
|
396 | + if(!$cr) { |
|
397 | + throw new \Exception('Could not connect to LDAP'); |
|
398 | + } |
|
399 | + |
|
400 | + $this->fetchGroups($dbKey, $confKey); |
|
401 | + |
|
402 | + if($testMemberOf) { |
|
403 | + $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); |
|
404 | + $this->result->markChange(); |
|
405 | + if(!$this->configuration->hasMemberOfFilterSupport) { |
|
406 | + throw new \Exception('memberOf is not supported by the server'); |
|
407 | + } |
|
408 | + } |
|
409 | + |
|
410 | + return $this->result; |
|
411 | + } |
|
412 | + |
|
413 | + /** |
|
414 | + * fetches all groups from LDAP and adds them to the result object |
|
415 | + * |
|
416 | + * @param string $dbKey |
|
417 | + * @param string $confKey |
|
418 | + * @return array $groupEntries |
|
419 | + * @throws \Exception |
|
420 | + */ |
|
421 | + public function fetchGroups($dbKey, $confKey) { |
|
422 | + $obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames'); |
|
423 | + |
|
424 | + $filterParts = array(); |
|
425 | + foreach($obclasses as $obclass) { |
|
426 | + $filterParts[] = 'objectclass='.$obclass; |
|
427 | + } |
|
428 | + //we filter for everything |
|
429 | + //- that looks like a group and |
|
430 | + //- has the group display name set |
|
431 | + $filter = $this->access->combineFilterWithOr($filterParts); |
|
432 | + $filter = $this->access->combineFilterWithAnd(array($filter, 'cn=*')); |
|
433 | + |
|
434 | + $groupNames = array(); |
|
435 | + $groupEntries = array(); |
|
436 | + $limit = 400; |
|
437 | + $offset = 0; |
|
438 | + do { |
|
439 | + // we need to request dn additionally here, otherwise memberOf |
|
440 | + // detection will fail later |
|
441 | + $result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset); |
|
442 | + foreach($result as $item) { |
|
443 | + if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) { |
|
444 | + // just in case - no issue known |
|
445 | + continue; |
|
446 | + } |
|
447 | + $groupNames[] = $item['cn'][0]; |
|
448 | + $groupEntries[] = $item; |
|
449 | + } |
|
450 | + $offset += $limit; |
|
451 | + } while ($this->access->hasMoreResults()); |
|
452 | + |
|
453 | + if(count($groupNames) > 0) { |
|
454 | + natsort($groupNames); |
|
455 | + $this->result->addOptions($dbKey, array_values($groupNames)); |
|
456 | + } else { |
|
457 | + throw new \Exception(self::$l->t('Could not find the desired feature')); |
|
458 | + } |
|
459 | + |
|
460 | + $setFeatures = $this->configuration->$confKey; |
|
461 | + if(is_array($setFeatures) && !empty($setFeatures)) { |
|
462 | + //something is already configured? pre-select it. |
|
463 | + $this->result->addChange($dbKey, $setFeatures); |
|
464 | + } |
|
465 | + return $groupEntries; |
|
466 | + } |
|
467 | + |
|
468 | + public function determineGroupMemberAssoc() { |
|
469 | + if(!$this->checkRequirements(array('ldapHost', |
|
470 | + 'ldapPort', |
|
471 | + 'ldapGroupFilter', |
|
472 | + ))) { |
|
473 | + return false; |
|
474 | + } |
|
475 | + $attribute = $this->detectGroupMemberAssoc(); |
|
476 | + if($attribute === false) { |
|
477 | + return false; |
|
478 | + } |
|
479 | + $this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute)); |
|
480 | + $this->result->addChange('ldap_group_member_assoc_attribute', $attribute); |
|
481 | + |
|
482 | + return $this->result; |
|
483 | + } |
|
484 | + |
|
485 | + /** |
|
486 | + * Detects the available object classes |
|
487 | + * @return WizardResult|false the instance's WizardResult instance |
|
488 | + * @throws \Exception |
|
489 | + */ |
|
490 | + public function determineGroupObjectClasses() { |
|
491 | + if(!$this->checkRequirements(array('ldapHost', |
|
492 | + 'ldapPort', |
|
493 | + 'ldapBase', |
|
494 | + ))) { |
|
495 | + return false; |
|
496 | + } |
|
497 | + $cr = $this->getConnection(); |
|
498 | + if(!$cr) { |
|
499 | + throw new \Exception('Could not connect to LDAP'); |
|
500 | + } |
|
501 | + |
|
502 | + $obclasses = array('groupOfNames', 'groupOfUniqueNames', 'group', 'posixGroup', '*'); |
|
503 | + $this->determineFeature($obclasses, |
|
504 | + 'objectclass', |
|
505 | + 'ldap_groupfilter_objectclass', |
|
506 | + 'ldapGroupFilterObjectclass', |
|
507 | + false); |
|
508 | + |
|
509 | + return $this->result; |
|
510 | + } |
|
511 | + |
|
512 | + /** |
|
513 | + * detects the available object classes |
|
514 | + * @return WizardResult |
|
515 | + * @throws \Exception |
|
516 | + */ |
|
517 | + public function determineUserObjectClasses() { |
|
518 | + if(!$this->checkRequirements(array('ldapHost', |
|
519 | + 'ldapPort', |
|
520 | + 'ldapBase', |
|
521 | + ))) { |
|
522 | + return false; |
|
523 | + } |
|
524 | + $cr = $this->getConnection(); |
|
525 | + if(!$cr) { |
|
526 | + throw new \Exception('Could not connect to LDAP'); |
|
527 | + } |
|
528 | + |
|
529 | + $obclasses = array('inetOrgPerson', 'person', 'organizationalPerson', |
|
530 | + 'user', 'posixAccount', '*'); |
|
531 | + $filter = $this->configuration->ldapUserFilter; |
|
532 | + //if filter is empty, it is probably the first time the wizard is called |
|
533 | + //then, apply suggestions. |
|
534 | + $this->determineFeature($obclasses, |
|
535 | + 'objectclass', |
|
536 | + 'ldap_userfilter_objectclass', |
|
537 | + 'ldapUserFilterObjectclass', |
|
538 | + empty($filter)); |
|
539 | + |
|
540 | + return $this->result; |
|
541 | + } |
|
542 | + |
|
543 | + /** |
|
544 | + * @return WizardResult|false |
|
545 | + * @throws \Exception |
|
546 | + */ |
|
547 | + public function getGroupFilter() { |
|
548 | + if(!$this->checkRequirements(array('ldapHost', |
|
549 | + 'ldapPort', |
|
550 | + 'ldapBase', |
|
551 | + ))) { |
|
552 | + return false; |
|
553 | + } |
|
554 | + //make sure the use display name is set |
|
555 | + $displayName = $this->configuration->ldapGroupDisplayName; |
|
556 | + if ($displayName === '') { |
|
557 | + $d = $this->configuration->getDefaults(); |
|
558 | + $this->applyFind('ldap_group_display_name', |
|
559 | + $d['ldap_group_display_name']); |
|
560 | + } |
|
561 | + $filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST); |
|
562 | + |
|
563 | + $this->applyFind('ldap_group_filter', $filter); |
|
564 | + return $this->result; |
|
565 | + } |
|
566 | + |
|
567 | + /** |
|
568 | + * @return WizardResult|false |
|
569 | + * @throws \Exception |
|
570 | + */ |
|
571 | + public function getUserListFilter() { |
|
572 | + if(!$this->checkRequirements(array('ldapHost', |
|
573 | + 'ldapPort', |
|
574 | + 'ldapBase', |
|
575 | + ))) { |
|
576 | + return false; |
|
577 | + } |
|
578 | + //make sure the use display name is set |
|
579 | + $displayName = $this->configuration->ldapUserDisplayName; |
|
580 | + if ($displayName === '') { |
|
581 | + $d = $this->configuration->getDefaults(); |
|
582 | + $this->applyFind('ldap_display_name', $d['ldap_display_name']); |
|
583 | + } |
|
584 | + $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST); |
|
585 | + if(!$filter) { |
|
586 | + throw new \Exception('Cannot create filter'); |
|
587 | + } |
|
588 | + |
|
589 | + $this->applyFind('ldap_userlist_filter', $filter); |
|
590 | + return $this->result; |
|
591 | + } |
|
592 | + |
|
593 | + /** |
|
594 | + * @return bool|WizardResult |
|
595 | + * @throws \Exception |
|
596 | + */ |
|
597 | + public function getUserLoginFilter() { |
|
598 | + if(!$this->checkRequirements(array('ldapHost', |
|
599 | + 'ldapPort', |
|
600 | + 'ldapBase', |
|
601 | + 'ldapUserFilter', |
|
602 | + ))) { |
|
603 | + return false; |
|
604 | + } |
|
605 | + |
|
606 | + $filter = $this->composeLdapFilter(self::LFILTER_LOGIN); |
|
607 | + if(!$filter) { |
|
608 | + throw new \Exception('Cannot create filter'); |
|
609 | + } |
|
610 | + |
|
611 | + $this->applyFind('ldap_login_filter', $filter); |
|
612 | + return $this->result; |
|
613 | + } |
|
614 | + |
|
615 | + /** |
|
616 | + * @return bool|WizardResult |
|
617 | + * @param string $loginName |
|
618 | + * @throws \Exception |
|
619 | + */ |
|
620 | + public function testLoginName($loginName) { |
|
621 | + if(!$this->checkRequirements(array('ldapHost', |
|
622 | + 'ldapPort', |
|
623 | + 'ldapBase', |
|
624 | + 'ldapLoginFilter', |
|
625 | + ))) { |
|
626 | + return false; |
|
627 | + } |
|
628 | + |
|
629 | + $cr = $this->access->connection->getConnectionResource(); |
|
630 | + if(!$this->ldap->isResource($cr)) { |
|
631 | + throw new \Exception('connection error'); |
|
632 | + } |
|
633 | + |
|
634 | + if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8') |
|
635 | + === false) { |
|
636 | + throw new \Exception('missing placeholder'); |
|
637 | + } |
|
638 | + |
|
639 | + $users = $this->access->countUsersByLoginName($loginName); |
|
640 | + if($this->ldap->errno($cr) !== 0) { |
|
641 | + throw new \Exception($this->ldap->error($cr)); |
|
642 | + } |
|
643 | + $filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter); |
|
644 | + $this->result->addChange('ldap_test_loginname', $users); |
|
645 | + $this->result->addChange('ldap_test_effective_filter', $filter); |
|
646 | + return $this->result; |
|
647 | + } |
|
648 | + |
|
649 | + /** |
|
650 | + * Tries to determine the port, requires given Host, User DN and Password |
|
651 | + * @return WizardResult|false WizardResult on success, false otherwise |
|
652 | + * @throws \Exception |
|
653 | + */ |
|
654 | + public function guessPortAndTLS() { |
|
655 | + if(!$this->checkRequirements(array('ldapHost', |
|
656 | + ))) { |
|
657 | + return false; |
|
658 | + } |
|
659 | + $this->checkHost(); |
|
660 | + $portSettings = $this->getPortSettingsToTry(); |
|
661 | + |
|
662 | + if(!is_array($portSettings)) { |
|
663 | + throw new \Exception(print_r($portSettings, true)); |
|
664 | + } |
|
665 | + |
|
666 | + //proceed from the best configuration and return on first success |
|
667 | + foreach($portSettings as $setting) { |
|
668 | + $p = $setting['port']; |
|
669 | + $t = $setting['tls']; |
|
670 | + \OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG); |
|
671 | + //connectAndBind may throw Exception, it needs to be catched by the |
|
672 | + //callee of this method |
|
673 | + |
|
674 | + try { |
|
675 | + $settingsFound = $this->connectAndBind($p, $t); |
|
676 | + } catch (\Exception $e) { |
|
677 | + // any reply other than -1 (= cannot connect) is already okay, |
|
678 | + // because then we found the server |
|
679 | + // unavailable startTLS returns -11 |
|
680 | + if($e->getCode() > 0) { |
|
681 | + $settingsFound = true; |
|
682 | + } else { |
|
683 | + throw $e; |
|
684 | + } |
|
685 | + } |
|
686 | + |
|
687 | + if ($settingsFound === true) { |
|
688 | + $config = array( |
|
689 | + 'ldapPort' => $p, |
|
690 | + 'ldapTLS' => intval($t) |
|
691 | + ); |
|
692 | + $this->configuration->setConfiguration($config); |
|
693 | + \OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG); |
|
694 | + $this->result->addChange('ldap_port', $p); |
|
695 | + return $this->result; |
|
696 | + } |
|
697 | + } |
|
698 | + |
|
699 | + //custom port, undetected (we do not brute force) |
|
700 | + return false; |
|
701 | + } |
|
702 | + |
|
703 | + /** |
|
704 | + * tries to determine a base dn from User DN or LDAP Host |
|
705 | + * @return WizardResult|false WizardResult on success, false otherwise |
|
706 | + */ |
|
707 | + public function guessBaseDN() { |
|
708 | + if(!$this->checkRequirements(array('ldapHost', |
|
709 | + 'ldapPort', |
|
710 | + ))) { |
|
711 | + return false; |
|
712 | + } |
|
713 | + |
|
714 | + //check whether a DN is given in the agent name (99.9% of all cases) |
|
715 | + $base = null; |
|
716 | + $i = stripos($this->configuration->ldapAgentName, 'dc='); |
|
717 | + if($i !== false) { |
|
718 | + $base = substr($this->configuration->ldapAgentName, $i); |
|
719 | + if($this->testBaseDN($base)) { |
|
720 | + $this->applyFind('ldap_base', $base); |
|
721 | + return $this->result; |
|
722 | + } |
|
723 | + } |
|
724 | + |
|
725 | + //this did not help :( |
|
726 | + //Let's see whether we can parse the Host URL and convert the domain to |
|
727 | + //a base DN |
|
728 | + $helper = new Helper(\OC::$server->getConfig()); |
|
729 | + $domain = $helper->getDomainFromURL($this->configuration->ldapHost); |
|
730 | + if(!$domain) { |
|
731 | + return false; |
|
732 | + } |
|
733 | + |
|
734 | + $dparts = explode('.', $domain); |
|
735 | + while(count($dparts) > 0) { |
|
736 | + $base2 = 'dc=' . implode(',dc=', $dparts); |
|
737 | + if ($base !== $base2 && $this->testBaseDN($base2)) { |
|
738 | + $this->applyFind('ldap_base', $base2); |
|
739 | + return $this->result; |
|
740 | + } |
|
741 | + array_shift($dparts); |
|
742 | + } |
|
743 | + |
|
744 | + return false; |
|
745 | + } |
|
746 | + |
|
747 | + /** |
|
748 | + * sets the found value for the configuration key in the WizardResult |
|
749 | + * as well as in the Configuration instance |
|
750 | + * @param string $key the configuration key |
|
751 | + * @param string $value the (detected) value |
|
752 | + * |
|
753 | + */ |
|
754 | + private function applyFind($key, $value) { |
|
755 | + $this->result->addChange($key, $value); |
|
756 | + $this->configuration->setConfiguration(array($key => $value)); |
|
757 | + } |
|
758 | + |
|
759 | + /** |
|
760 | + * Checks, whether a port was entered in the Host configuration |
|
761 | + * field. In this case the port will be stripped off, but also stored as |
|
762 | + * setting. |
|
763 | + */ |
|
764 | + private function checkHost() { |
|
765 | + $host = $this->configuration->ldapHost; |
|
766 | + $hostInfo = parse_url($host); |
|
767 | + |
|
768 | + //removes Port from Host |
|
769 | + if(is_array($hostInfo) && isset($hostInfo['port'])) { |
|
770 | + $port = $hostInfo['port']; |
|
771 | + $host = str_replace(':'.$port, '', $host); |
|
772 | + $this->applyFind('ldap_host', $host); |
|
773 | + $this->applyFind('ldap_port', $port); |
|
774 | + } |
|
775 | + } |
|
776 | + |
|
777 | + /** |
|
778 | + * tries to detect the group member association attribute which is |
|
779 | + * one of 'uniqueMember', 'memberUid', 'member', 'gidNumber' |
|
780 | + * @return string|false, string with the attribute name, false on error |
|
781 | + * @throws \Exception |
|
782 | + */ |
|
783 | + private function detectGroupMemberAssoc() { |
|
784 | + $possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'gidNumber'); |
|
785 | + $filter = $this->configuration->ldapGroupFilter; |
|
786 | + if(empty($filter)) { |
|
787 | + return false; |
|
788 | + } |
|
789 | + $cr = $this->getConnection(); |
|
790 | + if(!$cr) { |
|
791 | + throw new \Exception('Could not connect to LDAP'); |
|
792 | + } |
|
793 | + $base = $this->configuration->ldapBase[0]; |
|
794 | + $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000); |
|
795 | + if(!$this->ldap->isResource($rr)) { |
|
796 | + return false; |
|
797 | + } |
|
798 | + $er = $this->ldap->firstEntry($cr, $rr); |
|
799 | + while(is_resource($er)) { |
|
800 | + $this->ldap->getDN($cr, $er); |
|
801 | + $attrs = $this->ldap->getAttributes($cr, $er); |
|
802 | + $result = array(); |
|
803 | + $possibleAttrsCount = count($possibleAttrs); |
|
804 | + for($i = 0; $i < $possibleAttrsCount; $i++) { |
|
805 | + if(isset($attrs[$possibleAttrs[$i]])) { |
|
806 | + $result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count']; |
|
807 | + } |
|
808 | + } |
|
809 | + if(!empty($result)) { |
|
810 | + natsort($result); |
|
811 | + return key($result); |
|
812 | + } |
|
813 | + |
|
814 | + $er = $this->ldap->nextEntry($cr, $er); |
|
815 | + } |
|
816 | + |
|
817 | + return false; |
|
818 | + } |
|
819 | + |
|
820 | + /** |
|
821 | + * Checks whether for a given BaseDN results will be returned |
|
822 | + * @param string $base the BaseDN to test |
|
823 | + * @return bool true on success, false otherwise |
|
824 | + * @throws \Exception |
|
825 | + */ |
|
826 | + private function testBaseDN($base) { |
|
827 | + $cr = $this->getConnection(); |
|
828 | + if(!$cr) { |
|
829 | + throw new \Exception('Could not connect to LDAP'); |
|
830 | + } |
|
831 | + |
|
832 | + //base is there, let's validate it. If we search for anything, we should |
|
833 | + //get a result set > 0 on a proper base |
|
834 | + $rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1); |
|
835 | + if(!$this->ldap->isResource($rr)) { |
|
836 | + $errorNo = $this->ldap->errno($cr); |
|
837 | + $errorMsg = $this->ldap->error($cr); |
|
838 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base. |
|
839 | + ' Error '.$errorNo.': '.$errorMsg, \OCP\Util::INFO); |
|
840 | + return false; |
|
841 | + } |
|
842 | + $entries = $this->ldap->countEntries($cr, $rr); |
|
843 | + return ($entries !== false) && ($entries > 0); |
|
844 | + } |
|
845 | + |
|
846 | + /** |
|
847 | + * Checks whether the server supports memberOf in LDAP Filter. |
|
848 | + * Note: at least in OpenLDAP, availability of memberOf is dependent on |
|
849 | + * a configured objectClass. I.e. not necessarily for all available groups |
|
850 | + * memberOf does work. |
|
851 | + * |
|
852 | + * @return bool true if it does, false otherwise |
|
853 | + * @throws \Exception |
|
854 | + */ |
|
855 | + private function testMemberOf() { |
|
856 | + $cr = $this->getConnection(); |
|
857 | + if(!$cr) { |
|
858 | + throw new \Exception('Could not connect to LDAP'); |
|
859 | + } |
|
860 | + $result = $this->access->countUsers('memberOf=*', array('memberOf'), 1); |
|
861 | + if(is_int($result) && $result > 0) { |
|
862 | + return true; |
|
863 | + } |
|
864 | + return false; |
|
865 | + } |
|
866 | + |
|
867 | + /** |
|
868 | + * creates an LDAP Filter from given configuration |
|
869 | + * @param integer $filterType int, for which use case the filter shall be created |
|
870 | + * can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or |
|
871 | + * self::LFILTER_GROUP_LIST |
|
872 | + * @return string|false string with the filter on success, false otherwise |
|
873 | + * @throws \Exception |
|
874 | + */ |
|
875 | + private function composeLdapFilter($filterType) { |
|
876 | + $filter = ''; |
|
877 | + $parts = 0; |
|
878 | + switch ($filterType) { |
|
879 | + case self::LFILTER_USER_LIST: |
|
880 | + $objcs = $this->configuration->ldapUserFilterObjectclass; |
|
881 | + //glue objectclasses |
|
882 | + if(is_array($objcs) && count($objcs) > 0) { |
|
883 | + $filter .= '(|'; |
|
884 | + foreach($objcs as $objc) { |
|
885 | + $filter .= '(objectclass=' . $objc . ')'; |
|
886 | + } |
|
887 | + $filter .= ')'; |
|
888 | + $parts++; |
|
889 | + } |
|
890 | + //glue group memberships |
|
891 | + if($this->configuration->hasMemberOfFilterSupport) { |
|
892 | + $cns = $this->configuration->ldapUserFilterGroups; |
|
893 | + if(is_array($cns) && count($cns) > 0) { |
|
894 | + $filter .= '(|'; |
|
895 | + $cr = $this->getConnection(); |
|
896 | + if(!$cr) { |
|
897 | + throw new \Exception('Could not connect to LDAP'); |
|
898 | + } |
|
899 | + $base = $this->configuration->ldapBase[0]; |
|
900 | + foreach($cns as $cn) { |
|
901 | + $rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken')); |
|
902 | + if(!$this->ldap->isResource($rr)) { |
|
903 | + continue; |
|
904 | + } |
|
905 | + $er = $this->ldap->firstEntry($cr, $rr); |
|
906 | + $attrs = $this->ldap->getAttributes($cr, $er); |
|
907 | + $dn = $this->ldap->getDN($cr, $er); |
|
908 | + if ($dn == false || $dn === '') { |
|
909 | + continue; |
|
910 | + } |
|
911 | + $filterPart = '(memberof=' . $dn . ')'; |
|
912 | + if(isset($attrs['primaryGroupToken'])) { |
|
913 | + $pgt = $attrs['primaryGroupToken'][0]; |
|
914 | + $primaryFilterPart = '(primaryGroupID=' . $pgt .')'; |
|
915 | + $filterPart = '(|' . $filterPart . $primaryFilterPart . ')'; |
|
916 | + } |
|
917 | + $filter .= $filterPart; |
|
918 | + } |
|
919 | + $filter .= ')'; |
|
920 | + } |
|
921 | + $parts++; |
|
922 | + } |
|
923 | + //wrap parts in AND condition |
|
924 | + if($parts > 1) { |
|
925 | + $filter = '(&' . $filter . ')'; |
|
926 | + } |
|
927 | + if ($filter === '') { |
|
928 | + $filter = '(objectclass=*)'; |
|
929 | + } |
|
930 | + break; |
|
931 | + |
|
932 | + case self::LFILTER_GROUP_LIST: |
|
933 | + $objcs = $this->configuration->ldapGroupFilterObjectclass; |
|
934 | + //glue objectclasses |
|
935 | + if(is_array($objcs) && count($objcs) > 0) { |
|
936 | + $filter .= '(|'; |
|
937 | + foreach($objcs as $objc) { |
|
938 | + $filter .= '(objectclass=' . $objc . ')'; |
|
939 | + } |
|
940 | + $filter .= ')'; |
|
941 | + $parts++; |
|
942 | + } |
|
943 | + //glue group memberships |
|
944 | + $cns = $this->configuration->ldapGroupFilterGroups; |
|
945 | + if(is_array($cns) && count($cns) > 0) { |
|
946 | + $filter .= '(|'; |
|
947 | + foreach($cns as $cn) { |
|
948 | + $filter .= '(cn=' . $cn . ')'; |
|
949 | + } |
|
950 | + $filter .= ')'; |
|
951 | + } |
|
952 | + $parts++; |
|
953 | + //wrap parts in AND condition |
|
954 | + if($parts > 1) { |
|
955 | + $filter = '(&' . $filter . ')'; |
|
956 | + } |
|
957 | + break; |
|
958 | + |
|
959 | + case self::LFILTER_LOGIN: |
|
960 | + $ulf = $this->configuration->ldapUserFilter; |
|
961 | + $loginpart = '=%uid'; |
|
962 | + $filterUsername = ''; |
|
963 | + $userAttributes = $this->getUserAttributes(); |
|
964 | + $userAttributes = array_change_key_case(array_flip($userAttributes)); |
|
965 | + $parts = 0; |
|
966 | + |
|
967 | + if($this->configuration->ldapLoginFilterUsername === '1') { |
|
968 | + $attr = ''; |
|
969 | + if(isset($userAttributes['uid'])) { |
|
970 | + $attr = 'uid'; |
|
971 | + } else if(isset($userAttributes['samaccountname'])) { |
|
972 | + $attr = 'samaccountname'; |
|
973 | + } else if(isset($userAttributes['cn'])) { |
|
974 | + //fallback |
|
975 | + $attr = 'cn'; |
|
976 | + } |
|
977 | + if ($attr !== '') { |
|
978 | + $filterUsername = '(' . $attr . $loginpart . ')'; |
|
979 | + $parts++; |
|
980 | + } |
|
981 | + } |
|
982 | + |
|
983 | + $filterEmail = ''; |
|
984 | + if($this->configuration->ldapLoginFilterEmail === '1') { |
|
985 | + $filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))'; |
|
986 | + $parts++; |
|
987 | + } |
|
988 | + |
|
989 | + $filterAttributes = ''; |
|
990 | + $attrsToFilter = $this->configuration->ldapLoginFilterAttributes; |
|
991 | + if(is_array($attrsToFilter) && count($attrsToFilter) > 0) { |
|
992 | + $filterAttributes = '(|'; |
|
993 | + foreach($attrsToFilter as $attribute) { |
|
994 | + $filterAttributes .= '(' . $attribute . $loginpart . ')'; |
|
995 | + } |
|
996 | + $filterAttributes .= ')'; |
|
997 | + $parts++; |
|
998 | + } |
|
999 | + |
|
1000 | + $filterLogin = ''; |
|
1001 | + if($parts > 1) { |
|
1002 | + $filterLogin = '(|'; |
|
1003 | + } |
|
1004 | + $filterLogin .= $filterUsername; |
|
1005 | + $filterLogin .= $filterEmail; |
|
1006 | + $filterLogin .= $filterAttributes; |
|
1007 | + if($parts > 1) { |
|
1008 | + $filterLogin .= ')'; |
|
1009 | + } |
|
1010 | + |
|
1011 | + $filter = '(&'.$ulf.$filterLogin.')'; |
|
1012 | + break; |
|
1013 | + } |
|
1014 | + |
|
1015 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG); |
|
1016 | + |
|
1017 | + return $filter; |
|
1018 | + } |
|
1019 | + |
|
1020 | + /** |
|
1021 | + * Connects and Binds to an LDAP Server |
|
1022 | + * @param int $port the port to connect with |
|
1023 | + * @param bool $tls whether startTLS is to be used |
|
1024 | + * @param bool $ncc |
|
1025 | + * @return bool |
|
1026 | + * @throws \Exception |
|
1027 | + */ |
|
1028 | + private function connectAndBind($port = 389, $tls = false, $ncc = false) { |
|
1029 | + if($ncc) { |
|
1030 | + //No certificate check |
|
1031 | + //FIXME: undo afterwards |
|
1032 | + putenv('LDAPTLS_REQCERT=never'); |
|
1033 | + } |
|
1034 | + |
|
1035 | + //connect, does not really trigger any server communication |
|
1036 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Checking Host Info ', \OCP\Util::DEBUG); |
|
1037 | + $host = $this->configuration->ldapHost; |
|
1038 | + $hostInfo = parse_url($host); |
|
1039 | + if(!$hostInfo) { |
|
1040 | + throw new \Exception(self::$l->t('Invalid Host')); |
|
1041 | + } |
|
1042 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG); |
|
1043 | + $cr = $this->ldap->connect($host, $port); |
|
1044 | + if(!is_resource($cr)) { |
|
1045 | + throw new \Exception(self::$l->t('Invalid Host')); |
|
1046 | + } |
|
1047 | + |
|
1048 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Setting LDAP Options ', \OCP\Util::DEBUG); |
|
1049 | + //set LDAP options |
|
1050 | + $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); |
|
1051 | + $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0); |
|
1052 | + $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); |
|
1053 | + |
|
1054 | + try { |
|
1055 | + if($tls) { |
|
1056 | + $isTlsWorking = @$this->ldap->startTls($cr); |
|
1057 | + if(!$isTlsWorking) { |
|
1058 | + return false; |
|
1059 | + } |
|
1060 | + } |
|
1061 | + |
|
1062 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG); |
|
1063 | + //interesting part: do the bind! |
|
1064 | + $login = $this->ldap->bind($cr, |
|
1065 | + $this->configuration->ldapAgentName, |
|
1066 | + $this->configuration->ldapAgentPassword |
|
1067 | + ); |
|
1068 | + $errNo = $this->ldap->errno($cr); |
|
1069 | + $error = ldap_error($cr); |
|
1070 | + $this->ldap->unbind($cr); |
|
1071 | + } catch(ServerNotAvailableException $e) { |
|
1072 | + return false; |
|
1073 | + } |
|
1074 | + |
|
1075 | + if($login === true) { |
|
1076 | + $this->ldap->unbind($cr); |
|
1077 | + if($ncc) { |
|
1078 | + throw new \Exception('Certificate cannot be validated.'); |
|
1079 | + } |
|
1080 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . intval($tls), \OCP\Util::DEBUG); |
|
1081 | + return true; |
|
1082 | + } |
|
1083 | + |
|
1084 | + if($errNo === -1 || ($errNo === 2 && $ncc)) { |
|
1085 | + //host, port or TLS wrong |
|
1086 | + return false; |
|
1087 | + } else if ($errNo === 2) { |
|
1088 | + return $this->connectAndBind($port, $tls, true); |
|
1089 | + } |
|
1090 | + throw new \Exception($error, $errNo); |
|
1091 | + } |
|
1092 | + |
|
1093 | + /** |
|
1094 | + * checks whether a valid combination of agent and password has been |
|
1095 | + * provided (either two values or nothing for anonymous connect) |
|
1096 | + * @return bool, true if everything is fine, false otherwise |
|
1097 | + */ |
|
1098 | + private function checkAgentRequirements() { |
|
1099 | + $agent = $this->configuration->ldapAgentName; |
|
1100 | + $pwd = $this->configuration->ldapAgentPassword; |
|
1101 | + |
|
1102 | + return |
|
1103 | + ($agent !== '' && $pwd !== '') |
|
1104 | + || ($agent === '' && $pwd === '') |
|
1105 | + ; |
|
1106 | + } |
|
1107 | + |
|
1108 | + /** |
|
1109 | + * @param array $reqs |
|
1110 | + * @return bool |
|
1111 | + */ |
|
1112 | + private function checkRequirements($reqs) { |
|
1113 | + $this->checkAgentRequirements(); |
|
1114 | + foreach($reqs as $option) { |
|
1115 | + $value = $this->configuration->$option; |
|
1116 | + if(empty($value)) { |
|
1117 | + return false; |
|
1118 | + } |
|
1119 | + } |
|
1120 | + return true; |
|
1121 | + } |
|
1122 | + |
|
1123 | + /** |
|
1124 | + * does a cumulativeSearch on LDAP to get different values of a |
|
1125 | + * specified attribute |
|
1126 | + * @param string[] $filters array, the filters that shall be used in the search |
|
1127 | + * @param string $attr the attribute of which a list of values shall be returned |
|
1128 | + * @param int $dnReadLimit the amount of how many DNs should be analyzed. |
|
1129 | + * The lower, the faster |
|
1130 | + * @param string $maxF string. if not null, this variable will have the filter that |
|
1131 | + * yields most result entries |
|
1132 | + * @return array|false an array with the values on success, false otherwise |
|
1133 | + */ |
|
1134 | + public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) { |
|
1135 | + $dnRead = array(); |
|
1136 | + $foundItems = array(); |
|
1137 | + $maxEntries = 0; |
|
1138 | + if(!is_array($this->configuration->ldapBase) |
|
1139 | + || !isset($this->configuration->ldapBase[0])) { |
|
1140 | + return false; |
|
1141 | + } |
|
1142 | + $base = $this->configuration->ldapBase[0]; |
|
1143 | + $cr = $this->getConnection(); |
|
1144 | + if(!$this->ldap->isResource($cr)) { |
|
1145 | + return false; |
|
1146 | + } |
|
1147 | + $lastFilter = null; |
|
1148 | + if(isset($filters[count($filters)-1])) { |
|
1149 | + $lastFilter = $filters[count($filters)-1]; |
|
1150 | + } |
|
1151 | + foreach($filters as $filter) { |
|
1152 | + if($lastFilter === $filter && count($foundItems) > 0) { |
|
1153 | + //skip when the filter is a wildcard and results were found |
|
1154 | + continue; |
|
1155 | + } |
|
1156 | + // 20k limit for performance and reason |
|
1157 | + $rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000); |
|
1158 | + if(!$this->ldap->isResource($rr)) { |
|
1159 | + continue; |
|
1160 | + } |
|
1161 | + $entries = $this->ldap->countEntries($cr, $rr); |
|
1162 | + $getEntryFunc = 'firstEntry'; |
|
1163 | + if(($entries !== false) && ($entries > 0)) { |
|
1164 | + if(!is_null($maxF) && $entries > $maxEntries) { |
|
1165 | + $maxEntries = $entries; |
|
1166 | + $maxF = $filter; |
|
1167 | + } |
|
1168 | + $dnReadCount = 0; |
|
1169 | + do { |
|
1170 | + $entry = $this->ldap->$getEntryFunc($cr, $rr); |
|
1171 | + $getEntryFunc = 'nextEntry'; |
|
1172 | + if(!$this->ldap->isResource($entry)) { |
|
1173 | + continue 2; |
|
1174 | + } |
|
1175 | + $rr = $entry; //will be expected by nextEntry next round |
|
1176 | + $attributes = $this->ldap->getAttributes($cr, $entry); |
|
1177 | + $dn = $this->ldap->getDN($cr, $entry); |
|
1178 | + if($dn === false || in_array($dn, $dnRead)) { |
|
1179 | + continue; |
|
1180 | + } |
|
1181 | + $newItems = array(); |
|
1182 | + $state = $this->getAttributeValuesFromEntry($attributes, |
|
1183 | + $attr, |
|
1184 | + $newItems); |
|
1185 | + $dnReadCount++; |
|
1186 | + $foundItems = array_merge($foundItems, $newItems); |
|
1187 | + $this->resultCache[$dn][$attr] = $newItems; |
|
1188 | + $dnRead[] = $dn; |
|
1189 | + } while(($state === self::LRESULT_PROCESSED_SKIP |
|
1190 | + || $this->ldap->isResource($entry)) |
|
1191 | + && ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit)); |
|
1192 | + } |
|
1193 | + } |
|
1194 | + |
|
1195 | + return array_unique($foundItems); |
|
1196 | + } |
|
1197 | + |
|
1198 | + /** |
|
1199 | + * determines if and which $attr are available on the LDAP server |
|
1200 | + * @param string[] $objectclasses the objectclasses to use as search filter |
|
1201 | + * @param string $attr the attribute to look for |
|
1202 | + * @param string $dbkey the dbkey of the setting the feature is connected to |
|
1203 | + * @param string $confkey the confkey counterpart for the $dbkey as used in the |
|
1204 | + * Configuration class |
|
1205 | + * @param bool $po whether the objectClass with most result entries |
|
1206 | + * shall be pre-selected via the result |
|
1207 | + * @return array|false list of found items. |
|
1208 | + * @throws \Exception |
|
1209 | + */ |
|
1210 | + private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) { |
|
1211 | + $cr = $this->getConnection(); |
|
1212 | + if(!$cr) { |
|
1213 | + throw new \Exception('Could not connect to LDAP'); |
|
1214 | + } |
|
1215 | + $p = 'objectclass='; |
|
1216 | + foreach($objectclasses as $key => $value) { |
|
1217 | + $objectclasses[$key] = $p.$value; |
|
1218 | + } |
|
1219 | + $maxEntryObjC = ''; |
|
1220 | + |
|
1221 | + //how deep to dig? |
|
1222 | + //When looking for objectclasses, testing few entries is sufficient, |
|
1223 | + $dig = 3; |
|
1224 | + |
|
1225 | + $availableFeatures = |
|
1226 | + $this->cumulativeSearchOnAttribute($objectclasses, $attr, |
|
1227 | + $dig, $maxEntryObjC); |
|
1228 | + if(is_array($availableFeatures) |
|
1229 | + && count($availableFeatures) > 0) { |
|
1230 | + natcasesort($availableFeatures); |
|
1231 | + //natcasesort keeps indices, but we must get rid of them for proper |
|
1232 | + //sorting in the web UI. Therefore: array_values |
|
1233 | + $this->result->addOptions($dbkey, array_values($availableFeatures)); |
|
1234 | + } else { |
|
1235 | + throw new \Exception(self::$l->t('Could not find the desired feature')); |
|
1236 | + } |
|
1237 | + |
|
1238 | + $setFeatures = $this->configuration->$confkey; |
|
1239 | + if(is_array($setFeatures) && !empty($setFeatures)) { |
|
1240 | + //something is already configured? pre-select it. |
|
1241 | + $this->result->addChange($dbkey, $setFeatures); |
|
1242 | + } else if ($po && $maxEntryObjC !== '') { |
|
1243 | + //pre-select objectclass with most result entries |
|
1244 | + $maxEntryObjC = str_replace($p, '', $maxEntryObjC); |
|
1245 | + $this->applyFind($dbkey, $maxEntryObjC); |
|
1246 | + $this->result->addChange($dbkey, $maxEntryObjC); |
|
1247 | + } |
|
1248 | + |
|
1249 | + return $availableFeatures; |
|
1250 | + } |
|
1251 | + |
|
1252 | + /** |
|
1253 | + * appends a list of values fr |
|
1254 | + * @param resource $result the return value from ldap_get_attributes |
|
1255 | + * @param string $attribute the attribute values to look for |
|
1256 | + * @param array &$known new values will be appended here |
|
1257 | + * @return int, state on of the class constants LRESULT_PROCESSED_OK, |
|
1258 | + * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP |
|
1259 | + */ |
|
1260 | + private function getAttributeValuesFromEntry($result, $attribute, &$known) { |
|
1261 | + if(!is_array($result) |
|
1262 | + || !isset($result['count']) |
|
1263 | + || !$result['count'] > 0) { |
|
1264 | + return self::LRESULT_PROCESSED_INVALID; |
|
1265 | + } |
|
1266 | + |
|
1267 | + // strtolower on all keys for proper comparison |
|
1268 | + $result = \OCP\Util::mb_array_change_key_case($result); |
|
1269 | + $attribute = strtolower($attribute); |
|
1270 | + if(isset($result[$attribute])) { |
|
1271 | + foreach($result[$attribute] as $key => $val) { |
|
1272 | + if($key === 'count') { |
|
1273 | + continue; |
|
1274 | + } |
|
1275 | + if(!in_array($val, $known)) { |
|
1276 | + $known[] = $val; |
|
1277 | + } |
|
1278 | + } |
|
1279 | + return self::LRESULT_PROCESSED_OK; |
|
1280 | + } else { |
|
1281 | + return self::LRESULT_PROCESSED_SKIP; |
|
1282 | + } |
|
1283 | + } |
|
1284 | + |
|
1285 | + /** |
|
1286 | + * @return bool|mixed |
|
1287 | + */ |
|
1288 | + private function getConnection() { |
|
1289 | + if(!is_null($this->cr)) { |
|
1290 | + return $this->cr; |
|
1291 | + } |
|
1292 | + |
|
1293 | + $cr = $this->ldap->connect( |
|
1294 | + $this->configuration->ldapHost, |
|
1295 | + $this->configuration->ldapPort |
|
1296 | + ); |
|
1297 | + |
|
1298 | + $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); |
|
1299 | + $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0); |
|
1300 | + $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); |
|
1301 | + if($this->configuration->ldapTLS === 1) { |
|
1302 | + $this->ldap->startTls($cr); |
|
1303 | + } |
|
1304 | + |
|
1305 | + $lo = @$this->ldap->bind($cr, |
|
1306 | + $this->configuration->ldapAgentName, |
|
1307 | + $this->configuration->ldapAgentPassword); |
|
1308 | + if($lo === true) { |
|
1309 | + $this->$cr = $cr; |
|
1310 | + return $cr; |
|
1311 | + } |
|
1312 | + |
|
1313 | + return false; |
|
1314 | + } |
|
1315 | + |
|
1316 | + /** |
|
1317 | + * @return array |
|
1318 | + */ |
|
1319 | + private function getDefaultLdapPortSettings() { |
|
1320 | + static $settings = array( |
|
1321 | + array('port' => 7636, 'tls' => false), |
|
1322 | + array('port' => 636, 'tls' => false), |
|
1323 | + array('port' => 7389, 'tls' => true), |
|
1324 | + array('port' => 389, 'tls' => true), |
|
1325 | + array('port' => 7389, 'tls' => false), |
|
1326 | + array('port' => 389, 'tls' => false), |
|
1327 | + ); |
|
1328 | + return $settings; |
|
1329 | + } |
|
1330 | + |
|
1331 | + /** |
|
1332 | + * @return array |
|
1333 | + */ |
|
1334 | + private function getPortSettingsToTry() { |
|
1335 | + //389 ← LDAP / Unencrypted or StartTLS |
|
1336 | + //636 ← LDAPS / SSL |
|
1337 | + //7xxx ← UCS. need to be checked first, because both ports may be open |
|
1338 | + $host = $this->configuration->ldapHost; |
|
1339 | + $port = intval($this->configuration->ldapPort); |
|
1340 | + $portSettings = array(); |
|
1341 | + |
|
1342 | + //In case the port is already provided, we will check this first |
|
1343 | + if($port > 0) { |
|
1344 | + $hostInfo = parse_url($host); |
|
1345 | + if(!(is_array($hostInfo) |
|
1346 | + && isset($hostInfo['scheme']) |
|
1347 | + && stripos($hostInfo['scheme'], 'ldaps') !== false)) { |
|
1348 | + $portSettings[] = array('port' => $port, 'tls' => true); |
|
1349 | + } |
|
1350 | + $portSettings[] =array('port' => $port, 'tls' => false); |
|
1351 | + } |
|
1352 | + |
|
1353 | + //default ports |
|
1354 | + $portSettings = array_merge($portSettings, |
|
1355 | + $this->getDefaultLdapPortSettings()); |
|
1356 | + |
|
1357 | + return $portSettings; |
|
1358 | + } |
|
1359 | 1359 | |
1360 | 1360 | |
1361 | 1361 | } |
@@ -68,7 +68,7 @@ discard block |
||
68 | 68 | public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) { |
69 | 69 | parent::__construct($ldap); |
70 | 70 | $this->configuration = $configuration; |
71 | - if(is_null(Wizard::$l)) { |
|
71 | + if (is_null(Wizard::$l)) { |
|
72 | 72 | Wizard::$l = \OC::$server->getL10N('user_ldap'); |
73 | 73 | } |
74 | 74 | $this->access = $access; |
@@ -76,7 +76,7 @@ discard block |
||
76 | 76 | } |
77 | 77 | |
78 | 78 | public function __destruct() { |
79 | - if($this->result->hasChanges()) { |
|
79 | + if ($this->result->hasChanges()) { |
|
80 | 80 | $this->configuration->saveConfiguration(); |
81 | 81 | } |
82 | 82 | } |
@@ -91,18 +91,18 @@ discard block |
||
91 | 91 | */ |
92 | 92 | public function countEntries($filter, $type) { |
93 | 93 | $reqs = array('ldapHost', 'ldapPort', 'ldapBase'); |
94 | - if($type === 'users') { |
|
94 | + if ($type === 'users') { |
|
95 | 95 | $reqs[] = 'ldapUserFilter'; |
96 | 96 | } |
97 | - if(!$this->checkRequirements($reqs)) { |
|
97 | + if (!$this->checkRequirements($reqs)) { |
|
98 | 98 | throw new \Exception('Requirements not met', 400); |
99 | 99 | } |
100 | 100 | |
101 | 101 | $attr = array('dn'); // default |
102 | 102 | $limit = 1001; |
103 | - if($type === 'groups') { |
|
104 | - $result = $this->access->countGroups($filter, $attr, $limit); |
|
105 | - } else if($type === 'users') { |
|
103 | + if ($type === 'groups') { |
|
104 | + $result = $this->access->countGroups($filter, $attr, $limit); |
|
105 | + } else if ($type === 'users') { |
|
106 | 106 | $result = $this->access->countUsers($filter, $attr, $limit); |
107 | 107 | } else if ($type === 'objects') { |
108 | 108 | $result = $this->access->countObjects($limit); |
@@ -122,7 +122,7 @@ discard block |
||
122 | 122 | */ |
123 | 123 | private function formatCountResult($count) { |
124 | 124 | $formatted = ($count !== false) ? $count : 0; |
125 | - if($formatted > 1000) { |
|
125 | + if ($formatted > 1000) { |
|
126 | 126 | $formatted = '> 1000'; |
127 | 127 | } |
128 | 128 | return $formatted; |
@@ -131,7 +131,7 @@ discard block |
||
131 | 131 | public function countGroups() { |
132 | 132 | $filter = $this->configuration->ldapGroupFilter; |
133 | 133 | |
134 | - if(empty($filter)) { |
|
134 | + if (empty($filter)) { |
|
135 | 135 | $output = self::$l->n('%s group found', '%s groups found', 0, array(0)); |
136 | 136 | $this->result->addChange('ldap_group_count', $output); |
137 | 137 | return $this->result; |
@@ -141,7 +141,7 @@ discard block |
||
141 | 141 | $groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups')); |
142 | 142 | } catch (\Exception $e) { |
143 | 143 | //400 can be ignored, 500 is forwarded |
144 | - if($e->getCode() === 500) { |
|
144 | + if ($e->getCode() === 500) { |
|
145 | 145 | throw $e; |
146 | 146 | } |
147 | 147 | return false; |
@@ -173,7 +173,7 @@ discard block |
||
173 | 173 | public function countInBaseDN() { |
174 | 174 | // we don't need to provide a filter in this case |
175 | 175 | $total = $this->countEntries(null, 'objects'); |
176 | - if($total === false) { |
|
176 | + if ($total === false) { |
|
177 | 177 | throw new \Exception('invalid results received'); |
178 | 178 | } |
179 | 179 | $this->result->addChange('ldap_test_base', $total); |
@@ -187,7 +187,7 @@ discard block |
||
187 | 187 | * @return int|bool |
188 | 188 | */ |
189 | 189 | public function countUsersWithAttribute($attr, $existsCheck = false) { |
190 | - if(!$this->checkRequirements(array('ldapHost', |
|
190 | + if (!$this->checkRequirements(array('ldapHost', |
|
191 | 191 | 'ldapPort', |
192 | 192 | 'ldapBase', |
193 | 193 | 'ldapUserFilter', |
@@ -197,7 +197,7 @@ discard block |
||
197 | 197 | |
198 | 198 | $filter = $this->access->combineFilterWithAnd(array( |
199 | 199 | $this->configuration->ldapUserFilter, |
200 | - $attr . '=*' |
|
200 | + $attr.'=*' |
|
201 | 201 | )); |
202 | 202 | |
203 | 203 | $limit = ($existsCheck === false) ? null : 1; |
@@ -212,7 +212,7 @@ discard block |
||
212 | 212 | * @throws \Exception |
213 | 213 | */ |
214 | 214 | public function detectUserDisplayNameAttribute() { |
215 | - if(!$this->checkRequirements(array('ldapHost', |
|
215 | + if (!$this->checkRequirements(array('ldapHost', |
|
216 | 216 | 'ldapPort', |
217 | 217 | 'ldapBase', |
218 | 218 | 'ldapUserFilter', |
@@ -225,7 +225,7 @@ discard block |
||
225 | 225 | // most likely not the default value with upper case N, |
226 | 226 | // verify it still produces a result |
227 | 227 | $count = intval($this->countUsersWithAttribute($attr, true)); |
228 | - if($count > 0) { |
|
228 | + if ($count > 0) { |
|
229 | 229 | //no change, but we sent it back to make sure the user interface |
230 | 230 | //is still correct, even if the ajax call was cancelled meanwhile |
231 | 231 | $this->result->addChange('ldap_display_name', $attr); |
@@ -238,7 +238,7 @@ discard block |
||
238 | 238 | foreach ($displayNameAttrs as $attr) { |
239 | 239 | $count = intval($this->countUsersWithAttribute($attr, true)); |
240 | 240 | |
241 | - if($count > 0) { |
|
241 | + if ($count > 0) { |
|
242 | 242 | $this->applyFind('ldap_display_name', $attr); |
243 | 243 | return $this->result; |
244 | 244 | } |
@@ -254,7 +254,7 @@ discard block |
||
254 | 254 | * @return WizardResult|bool |
255 | 255 | */ |
256 | 256 | public function detectEmailAttribute() { |
257 | - if(!$this->checkRequirements(array('ldapHost', |
|
257 | + if (!$this->checkRequirements(array('ldapHost', |
|
258 | 258 | 'ldapPort', |
259 | 259 | 'ldapBase', |
260 | 260 | 'ldapUserFilter', |
@@ -265,7 +265,7 @@ discard block |
||
265 | 265 | $attr = $this->configuration->ldapEmailAttribute; |
266 | 266 | if ($attr !== '') { |
267 | 267 | $count = intval($this->countUsersWithAttribute($attr, true)); |
268 | - if($count > 0) { |
|
268 | + if ($count > 0) { |
|
269 | 269 | return false; |
270 | 270 | } |
271 | 271 | $writeLog = true; |
@@ -276,19 +276,19 @@ discard block |
||
276 | 276 | $emailAttributes = array('mail', 'mailPrimaryAddress'); |
277 | 277 | $winner = ''; |
278 | 278 | $maxUsers = 0; |
279 | - foreach($emailAttributes as $attr) { |
|
279 | + foreach ($emailAttributes as $attr) { |
|
280 | 280 | $count = $this->countUsersWithAttribute($attr); |
281 | - if($count > $maxUsers) { |
|
281 | + if ($count > $maxUsers) { |
|
282 | 282 | $maxUsers = $count; |
283 | 283 | $winner = $attr; |
284 | 284 | } |
285 | 285 | } |
286 | 286 | |
287 | - if($winner !== '') { |
|
287 | + if ($winner !== '') { |
|
288 | 288 | $this->applyFind('ldap_email_attr', $winner); |
289 | - if($writeLog) { |
|
290 | - \OCP\Util::writeLog('user_ldap', 'The mail attribute has ' . |
|
291 | - 'automatically been reset, because the original value ' . |
|
289 | + if ($writeLog) { |
|
290 | + \OCP\Util::writeLog('user_ldap', 'The mail attribute has '. |
|
291 | + 'automatically been reset, because the original value '. |
|
292 | 292 | 'did not return any results.', \OCP\Util::INFO); |
293 | 293 | } |
294 | 294 | } |
@@ -301,7 +301,7 @@ discard block |
||
301 | 301 | * @throws \Exception |
302 | 302 | */ |
303 | 303 | public function determineAttributes() { |
304 | - if(!$this->checkRequirements(array('ldapHost', |
|
304 | + if (!$this->checkRequirements(array('ldapHost', |
|
305 | 305 | 'ldapPort', |
306 | 306 | 'ldapBase', |
307 | 307 | 'ldapUserFilter', |
@@ -317,7 +317,7 @@ discard block |
||
317 | 317 | $this->result->addOptions('ldap_loginfilter_attributes', $attributes); |
318 | 318 | |
319 | 319 | $selected = $this->configuration->ldapLoginFilterAttributes; |
320 | - if(is_array($selected) && !empty($selected)) { |
|
320 | + if (is_array($selected) && !empty($selected)) { |
|
321 | 321 | $this->result->addChange('ldap_loginfilter_attributes', $selected); |
322 | 322 | } |
323 | 323 | |
@@ -330,7 +330,7 @@ discard block |
||
330 | 330 | * @throws \Exception |
331 | 331 | */ |
332 | 332 | private function getUserAttributes() { |
333 | - if(!$this->checkRequirements(array('ldapHost', |
|
333 | + if (!$this->checkRequirements(array('ldapHost', |
|
334 | 334 | 'ldapPort', |
335 | 335 | 'ldapBase', |
336 | 336 | 'ldapUserFilter', |
@@ -338,20 +338,20 @@ discard block |
||
338 | 338 | return false; |
339 | 339 | } |
340 | 340 | $cr = $this->getConnection(); |
341 | - if(!$cr) { |
|
341 | + if (!$cr) { |
|
342 | 342 | throw new \Exception('Could not connect to LDAP'); |
343 | 343 | } |
344 | 344 | |
345 | 345 | $base = $this->configuration->ldapBase[0]; |
346 | 346 | $filter = $this->configuration->ldapUserFilter; |
347 | 347 | $rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1); |
348 | - if(!$this->ldap->isResource($rr)) { |
|
348 | + if (!$this->ldap->isResource($rr)) { |
|
349 | 349 | return false; |
350 | 350 | } |
351 | 351 | $er = $this->ldap->firstEntry($cr, $rr); |
352 | 352 | $attributes = $this->ldap->getAttributes($cr, $er); |
353 | 353 | $pureAttributes = array(); |
354 | - for($i = 0; $i < $attributes['count']; $i++) { |
|
354 | + for ($i = 0; $i < $attributes['count']; $i++) { |
|
355 | 355 | $pureAttributes[] = $attributes[$i]; |
356 | 356 | } |
357 | 357 | |
@@ -386,23 +386,23 @@ discard block |
||
386 | 386 | * @throws \Exception |
387 | 387 | */ |
388 | 388 | private function determineGroups($dbKey, $confKey, $testMemberOf = true) { |
389 | - if(!$this->checkRequirements(array('ldapHost', |
|
389 | + if (!$this->checkRequirements(array('ldapHost', |
|
390 | 390 | 'ldapPort', |
391 | 391 | 'ldapBase', |
392 | 392 | ))) { |
393 | 393 | return false; |
394 | 394 | } |
395 | 395 | $cr = $this->getConnection(); |
396 | - if(!$cr) { |
|
396 | + if (!$cr) { |
|
397 | 397 | throw new \Exception('Could not connect to LDAP'); |
398 | 398 | } |
399 | 399 | |
400 | 400 | $this->fetchGroups($dbKey, $confKey); |
401 | 401 | |
402 | - if($testMemberOf) { |
|
402 | + if ($testMemberOf) { |
|
403 | 403 | $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); |
404 | 404 | $this->result->markChange(); |
405 | - if(!$this->configuration->hasMemberOfFilterSupport) { |
|
405 | + if (!$this->configuration->hasMemberOfFilterSupport) { |
|
406 | 406 | throw new \Exception('memberOf is not supported by the server'); |
407 | 407 | } |
408 | 408 | } |
@@ -422,7 +422,7 @@ discard block |
||
422 | 422 | $obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames'); |
423 | 423 | |
424 | 424 | $filterParts = array(); |
425 | - foreach($obclasses as $obclass) { |
|
425 | + foreach ($obclasses as $obclass) { |
|
426 | 426 | $filterParts[] = 'objectclass='.$obclass; |
427 | 427 | } |
428 | 428 | //we filter for everything |
@@ -439,8 +439,8 @@ discard block |
||
439 | 439 | // we need to request dn additionally here, otherwise memberOf |
440 | 440 | // detection will fail later |
441 | 441 | $result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset); |
442 | - foreach($result as $item) { |
|
443 | - if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) { |
|
442 | + foreach ($result as $item) { |
|
443 | + if (!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) { |
|
444 | 444 | // just in case - no issue known |
445 | 445 | continue; |
446 | 446 | } |
@@ -450,7 +450,7 @@ discard block |
||
450 | 450 | $offset += $limit; |
451 | 451 | } while ($this->access->hasMoreResults()); |
452 | 452 | |
453 | - if(count($groupNames) > 0) { |
|
453 | + if (count($groupNames) > 0) { |
|
454 | 454 | natsort($groupNames); |
455 | 455 | $this->result->addOptions($dbKey, array_values($groupNames)); |
456 | 456 | } else { |
@@ -458,7 +458,7 @@ discard block |
||
458 | 458 | } |
459 | 459 | |
460 | 460 | $setFeatures = $this->configuration->$confKey; |
461 | - if(is_array($setFeatures) && !empty($setFeatures)) { |
|
461 | + if (is_array($setFeatures) && !empty($setFeatures)) { |
|
462 | 462 | //something is already configured? pre-select it. |
463 | 463 | $this->result->addChange($dbKey, $setFeatures); |
464 | 464 | } |
@@ -466,14 +466,14 @@ discard block |
||
466 | 466 | } |
467 | 467 | |
468 | 468 | public function determineGroupMemberAssoc() { |
469 | - if(!$this->checkRequirements(array('ldapHost', |
|
469 | + if (!$this->checkRequirements(array('ldapHost', |
|
470 | 470 | 'ldapPort', |
471 | 471 | 'ldapGroupFilter', |
472 | 472 | ))) { |
473 | 473 | return false; |
474 | 474 | } |
475 | 475 | $attribute = $this->detectGroupMemberAssoc(); |
476 | - if($attribute === false) { |
|
476 | + if ($attribute === false) { |
|
477 | 477 | return false; |
478 | 478 | } |
479 | 479 | $this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute)); |
@@ -488,14 +488,14 @@ discard block |
||
488 | 488 | * @throws \Exception |
489 | 489 | */ |
490 | 490 | public function determineGroupObjectClasses() { |
491 | - if(!$this->checkRequirements(array('ldapHost', |
|
491 | + if (!$this->checkRequirements(array('ldapHost', |
|
492 | 492 | 'ldapPort', |
493 | 493 | 'ldapBase', |
494 | 494 | ))) { |
495 | 495 | return false; |
496 | 496 | } |
497 | 497 | $cr = $this->getConnection(); |
498 | - if(!$cr) { |
|
498 | + if (!$cr) { |
|
499 | 499 | throw new \Exception('Could not connect to LDAP'); |
500 | 500 | } |
501 | 501 | |
@@ -515,14 +515,14 @@ discard block |
||
515 | 515 | * @throws \Exception |
516 | 516 | */ |
517 | 517 | public function determineUserObjectClasses() { |
518 | - if(!$this->checkRequirements(array('ldapHost', |
|
518 | + if (!$this->checkRequirements(array('ldapHost', |
|
519 | 519 | 'ldapPort', |
520 | 520 | 'ldapBase', |
521 | 521 | ))) { |
522 | 522 | return false; |
523 | 523 | } |
524 | 524 | $cr = $this->getConnection(); |
525 | - if(!$cr) { |
|
525 | + if (!$cr) { |
|
526 | 526 | throw new \Exception('Could not connect to LDAP'); |
527 | 527 | } |
528 | 528 | |
@@ -545,7 +545,7 @@ discard block |
||
545 | 545 | * @throws \Exception |
546 | 546 | */ |
547 | 547 | public function getGroupFilter() { |
548 | - if(!$this->checkRequirements(array('ldapHost', |
|
548 | + if (!$this->checkRequirements(array('ldapHost', |
|
549 | 549 | 'ldapPort', |
550 | 550 | 'ldapBase', |
551 | 551 | ))) { |
@@ -569,7 +569,7 @@ discard block |
||
569 | 569 | * @throws \Exception |
570 | 570 | */ |
571 | 571 | public function getUserListFilter() { |
572 | - if(!$this->checkRequirements(array('ldapHost', |
|
572 | + if (!$this->checkRequirements(array('ldapHost', |
|
573 | 573 | 'ldapPort', |
574 | 574 | 'ldapBase', |
575 | 575 | ))) { |
@@ -582,7 +582,7 @@ discard block |
||
582 | 582 | $this->applyFind('ldap_display_name', $d['ldap_display_name']); |
583 | 583 | } |
584 | 584 | $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST); |
585 | - if(!$filter) { |
|
585 | + if (!$filter) { |
|
586 | 586 | throw new \Exception('Cannot create filter'); |
587 | 587 | } |
588 | 588 | |
@@ -595,7 +595,7 @@ discard block |
||
595 | 595 | * @throws \Exception |
596 | 596 | */ |
597 | 597 | public function getUserLoginFilter() { |
598 | - if(!$this->checkRequirements(array('ldapHost', |
|
598 | + if (!$this->checkRequirements(array('ldapHost', |
|
599 | 599 | 'ldapPort', |
600 | 600 | 'ldapBase', |
601 | 601 | 'ldapUserFilter', |
@@ -604,7 +604,7 @@ discard block |
||
604 | 604 | } |
605 | 605 | |
606 | 606 | $filter = $this->composeLdapFilter(self::LFILTER_LOGIN); |
607 | - if(!$filter) { |
|
607 | + if (!$filter) { |
|
608 | 608 | throw new \Exception('Cannot create filter'); |
609 | 609 | } |
610 | 610 | |
@@ -618,7 +618,7 @@ discard block |
||
618 | 618 | * @throws \Exception |
619 | 619 | */ |
620 | 620 | public function testLoginName($loginName) { |
621 | - if(!$this->checkRequirements(array('ldapHost', |
|
621 | + if (!$this->checkRequirements(array('ldapHost', |
|
622 | 622 | 'ldapPort', |
623 | 623 | 'ldapBase', |
624 | 624 | 'ldapLoginFilter', |
@@ -627,17 +627,17 @@ discard block |
||
627 | 627 | } |
628 | 628 | |
629 | 629 | $cr = $this->access->connection->getConnectionResource(); |
630 | - if(!$this->ldap->isResource($cr)) { |
|
630 | + if (!$this->ldap->isResource($cr)) { |
|
631 | 631 | throw new \Exception('connection error'); |
632 | 632 | } |
633 | 633 | |
634 | - if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8') |
|
634 | + if (mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8') |
|
635 | 635 | === false) { |
636 | 636 | throw new \Exception('missing placeholder'); |
637 | 637 | } |
638 | 638 | |
639 | 639 | $users = $this->access->countUsersByLoginName($loginName); |
640 | - if($this->ldap->errno($cr) !== 0) { |
|
640 | + if ($this->ldap->errno($cr) !== 0) { |
|
641 | 641 | throw new \Exception($this->ldap->error($cr)); |
642 | 642 | } |
643 | 643 | $filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter); |
@@ -652,22 +652,22 @@ discard block |
||
652 | 652 | * @throws \Exception |
653 | 653 | */ |
654 | 654 | public function guessPortAndTLS() { |
655 | - if(!$this->checkRequirements(array('ldapHost', |
|
655 | + if (!$this->checkRequirements(array('ldapHost', |
|
656 | 656 | ))) { |
657 | 657 | return false; |
658 | 658 | } |
659 | 659 | $this->checkHost(); |
660 | 660 | $portSettings = $this->getPortSettingsToTry(); |
661 | 661 | |
662 | - if(!is_array($portSettings)) { |
|
662 | + if (!is_array($portSettings)) { |
|
663 | 663 | throw new \Exception(print_r($portSettings, true)); |
664 | 664 | } |
665 | 665 | |
666 | 666 | //proceed from the best configuration and return on first success |
667 | - foreach($portSettings as $setting) { |
|
667 | + foreach ($portSettings as $setting) { |
|
668 | 668 | $p = $setting['port']; |
669 | 669 | $t = $setting['tls']; |
670 | - \OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG); |
|
670 | + \OCP\Util::writeLog('user_ldap', 'Wiz: trying port '.$p.', TLS '.$t, \OCP\Util::DEBUG); |
|
671 | 671 | //connectAndBind may throw Exception, it needs to be catched by the |
672 | 672 | //callee of this method |
673 | 673 | |
@@ -677,7 +677,7 @@ discard block |
||
677 | 677 | // any reply other than -1 (= cannot connect) is already okay, |
678 | 678 | // because then we found the server |
679 | 679 | // unavailable startTLS returns -11 |
680 | - if($e->getCode() > 0) { |
|
680 | + if ($e->getCode() > 0) { |
|
681 | 681 | $settingsFound = true; |
682 | 682 | } else { |
683 | 683 | throw $e; |
@@ -690,7 +690,7 @@ discard block |
||
690 | 690 | 'ldapTLS' => intval($t) |
691 | 691 | ); |
692 | 692 | $this->configuration->setConfiguration($config); |
693 | - \OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG); |
|
693 | + \OCP\Util::writeLog('user_ldap', 'Wiz: detected Port '.$p, \OCP\Util::DEBUG); |
|
694 | 694 | $this->result->addChange('ldap_port', $p); |
695 | 695 | return $this->result; |
696 | 696 | } |
@@ -705,7 +705,7 @@ discard block |
||
705 | 705 | * @return WizardResult|false WizardResult on success, false otherwise |
706 | 706 | */ |
707 | 707 | public function guessBaseDN() { |
708 | - if(!$this->checkRequirements(array('ldapHost', |
|
708 | + if (!$this->checkRequirements(array('ldapHost', |
|
709 | 709 | 'ldapPort', |
710 | 710 | ))) { |
711 | 711 | return false; |
@@ -714,9 +714,9 @@ discard block |
||
714 | 714 | //check whether a DN is given in the agent name (99.9% of all cases) |
715 | 715 | $base = null; |
716 | 716 | $i = stripos($this->configuration->ldapAgentName, 'dc='); |
717 | - if($i !== false) { |
|
717 | + if ($i !== false) { |
|
718 | 718 | $base = substr($this->configuration->ldapAgentName, $i); |
719 | - if($this->testBaseDN($base)) { |
|
719 | + if ($this->testBaseDN($base)) { |
|
720 | 720 | $this->applyFind('ldap_base', $base); |
721 | 721 | return $this->result; |
722 | 722 | } |
@@ -727,13 +727,13 @@ discard block |
||
727 | 727 | //a base DN |
728 | 728 | $helper = new Helper(\OC::$server->getConfig()); |
729 | 729 | $domain = $helper->getDomainFromURL($this->configuration->ldapHost); |
730 | - if(!$domain) { |
|
730 | + if (!$domain) { |
|
731 | 731 | return false; |
732 | 732 | } |
733 | 733 | |
734 | 734 | $dparts = explode('.', $domain); |
735 | - while(count($dparts) > 0) { |
|
736 | - $base2 = 'dc=' . implode(',dc=', $dparts); |
|
735 | + while (count($dparts) > 0) { |
|
736 | + $base2 = 'dc='.implode(',dc=', $dparts); |
|
737 | 737 | if ($base !== $base2 && $this->testBaseDN($base2)) { |
738 | 738 | $this->applyFind('ldap_base', $base2); |
739 | 739 | return $this->result; |
@@ -766,7 +766,7 @@ discard block |
||
766 | 766 | $hostInfo = parse_url($host); |
767 | 767 | |
768 | 768 | //removes Port from Host |
769 | - if(is_array($hostInfo) && isset($hostInfo['port'])) { |
|
769 | + if (is_array($hostInfo) && isset($hostInfo['port'])) { |
|
770 | 770 | $port = $hostInfo['port']; |
771 | 771 | $host = str_replace(':'.$port, '', $host); |
772 | 772 | $this->applyFind('ldap_host', $host); |
@@ -783,30 +783,30 @@ discard block |
||
783 | 783 | private function detectGroupMemberAssoc() { |
784 | 784 | $possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'gidNumber'); |
785 | 785 | $filter = $this->configuration->ldapGroupFilter; |
786 | - if(empty($filter)) { |
|
786 | + if (empty($filter)) { |
|
787 | 787 | return false; |
788 | 788 | } |
789 | 789 | $cr = $this->getConnection(); |
790 | - if(!$cr) { |
|
790 | + if (!$cr) { |
|
791 | 791 | throw new \Exception('Could not connect to LDAP'); |
792 | 792 | } |
793 | 793 | $base = $this->configuration->ldapBase[0]; |
794 | 794 | $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000); |
795 | - if(!$this->ldap->isResource($rr)) { |
|
795 | + if (!$this->ldap->isResource($rr)) { |
|
796 | 796 | return false; |
797 | 797 | } |
798 | 798 | $er = $this->ldap->firstEntry($cr, $rr); |
799 | - while(is_resource($er)) { |
|
799 | + while (is_resource($er)) { |
|
800 | 800 | $this->ldap->getDN($cr, $er); |
801 | 801 | $attrs = $this->ldap->getAttributes($cr, $er); |
802 | 802 | $result = array(); |
803 | 803 | $possibleAttrsCount = count($possibleAttrs); |
804 | - for($i = 0; $i < $possibleAttrsCount; $i++) { |
|
805 | - if(isset($attrs[$possibleAttrs[$i]])) { |
|
804 | + for ($i = 0; $i < $possibleAttrsCount; $i++) { |
|
805 | + if (isset($attrs[$possibleAttrs[$i]])) { |
|
806 | 806 | $result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count']; |
807 | 807 | } |
808 | 808 | } |
809 | - if(!empty($result)) { |
|
809 | + if (!empty($result)) { |
|
810 | 810 | natsort($result); |
811 | 811 | return key($result); |
812 | 812 | } |
@@ -825,14 +825,14 @@ discard block |
||
825 | 825 | */ |
826 | 826 | private function testBaseDN($base) { |
827 | 827 | $cr = $this->getConnection(); |
828 | - if(!$cr) { |
|
828 | + if (!$cr) { |
|
829 | 829 | throw new \Exception('Could not connect to LDAP'); |
830 | 830 | } |
831 | 831 | |
832 | 832 | //base is there, let's validate it. If we search for anything, we should |
833 | 833 | //get a result set > 0 on a proper base |
834 | 834 | $rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1); |
835 | - if(!$this->ldap->isResource($rr)) { |
|
835 | + if (!$this->ldap->isResource($rr)) { |
|
836 | 836 | $errorNo = $this->ldap->errno($cr); |
837 | 837 | $errorMsg = $this->ldap->error($cr); |
838 | 838 | \OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base. |
@@ -854,11 +854,11 @@ discard block |
||
854 | 854 | */ |
855 | 855 | private function testMemberOf() { |
856 | 856 | $cr = $this->getConnection(); |
857 | - if(!$cr) { |
|
857 | + if (!$cr) { |
|
858 | 858 | throw new \Exception('Could not connect to LDAP'); |
859 | 859 | } |
860 | 860 | $result = $this->access->countUsers('memberOf=*', array('memberOf'), 1); |
861 | - if(is_int($result) && $result > 0) { |
|
861 | + if (is_int($result) && $result > 0) { |
|
862 | 862 | return true; |
863 | 863 | } |
864 | 864 | return false; |
@@ -879,27 +879,27 @@ discard block |
||
879 | 879 | case self::LFILTER_USER_LIST: |
880 | 880 | $objcs = $this->configuration->ldapUserFilterObjectclass; |
881 | 881 | //glue objectclasses |
882 | - if(is_array($objcs) && count($objcs) > 0) { |
|
882 | + if (is_array($objcs) && count($objcs) > 0) { |
|
883 | 883 | $filter .= '(|'; |
884 | - foreach($objcs as $objc) { |
|
885 | - $filter .= '(objectclass=' . $objc . ')'; |
|
884 | + foreach ($objcs as $objc) { |
|
885 | + $filter .= '(objectclass='.$objc.')'; |
|
886 | 886 | } |
887 | 887 | $filter .= ')'; |
888 | 888 | $parts++; |
889 | 889 | } |
890 | 890 | //glue group memberships |
891 | - if($this->configuration->hasMemberOfFilterSupport) { |
|
891 | + if ($this->configuration->hasMemberOfFilterSupport) { |
|
892 | 892 | $cns = $this->configuration->ldapUserFilterGroups; |
893 | - if(is_array($cns) && count($cns) > 0) { |
|
893 | + if (is_array($cns) && count($cns) > 0) { |
|
894 | 894 | $filter .= '(|'; |
895 | 895 | $cr = $this->getConnection(); |
896 | - if(!$cr) { |
|
896 | + if (!$cr) { |
|
897 | 897 | throw new \Exception('Could not connect to LDAP'); |
898 | 898 | } |
899 | 899 | $base = $this->configuration->ldapBase[0]; |
900 | - foreach($cns as $cn) { |
|
901 | - $rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken')); |
|
902 | - if(!$this->ldap->isResource($rr)) { |
|
900 | + foreach ($cns as $cn) { |
|
901 | + $rr = $this->ldap->search($cr, $base, 'cn='.$cn, array('dn', 'primaryGroupToken')); |
|
902 | + if (!$this->ldap->isResource($rr)) { |
|
903 | 903 | continue; |
904 | 904 | } |
905 | 905 | $er = $this->ldap->firstEntry($cr, $rr); |
@@ -908,11 +908,11 @@ discard block |
||
908 | 908 | if ($dn == false || $dn === '') { |
909 | 909 | continue; |
910 | 910 | } |
911 | - $filterPart = '(memberof=' . $dn . ')'; |
|
912 | - if(isset($attrs['primaryGroupToken'])) { |
|
911 | + $filterPart = '(memberof='.$dn.')'; |
|
912 | + if (isset($attrs['primaryGroupToken'])) { |
|
913 | 913 | $pgt = $attrs['primaryGroupToken'][0]; |
914 | - $primaryFilterPart = '(primaryGroupID=' . $pgt .')'; |
|
915 | - $filterPart = '(|' . $filterPart . $primaryFilterPart . ')'; |
|
914 | + $primaryFilterPart = '(primaryGroupID='.$pgt.')'; |
|
915 | + $filterPart = '(|'.$filterPart.$primaryFilterPart.')'; |
|
916 | 916 | } |
917 | 917 | $filter .= $filterPart; |
918 | 918 | } |
@@ -921,8 +921,8 @@ discard block |
||
921 | 921 | $parts++; |
922 | 922 | } |
923 | 923 | //wrap parts in AND condition |
924 | - if($parts > 1) { |
|
925 | - $filter = '(&' . $filter . ')'; |
|
924 | + if ($parts > 1) { |
|
925 | + $filter = '(&'.$filter.')'; |
|
926 | 926 | } |
927 | 927 | if ($filter === '') { |
928 | 928 | $filter = '(objectclass=*)'; |
@@ -932,27 +932,27 @@ discard block |
||
932 | 932 | case self::LFILTER_GROUP_LIST: |
933 | 933 | $objcs = $this->configuration->ldapGroupFilterObjectclass; |
934 | 934 | //glue objectclasses |
935 | - if(is_array($objcs) && count($objcs) > 0) { |
|
935 | + if (is_array($objcs) && count($objcs) > 0) { |
|
936 | 936 | $filter .= '(|'; |
937 | - foreach($objcs as $objc) { |
|
938 | - $filter .= '(objectclass=' . $objc . ')'; |
|
937 | + foreach ($objcs as $objc) { |
|
938 | + $filter .= '(objectclass='.$objc.')'; |
|
939 | 939 | } |
940 | 940 | $filter .= ')'; |
941 | 941 | $parts++; |
942 | 942 | } |
943 | 943 | //glue group memberships |
944 | 944 | $cns = $this->configuration->ldapGroupFilterGroups; |
945 | - if(is_array($cns) && count($cns) > 0) { |
|
945 | + if (is_array($cns) && count($cns) > 0) { |
|
946 | 946 | $filter .= '(|'; |
947 | - foreach($cns as $cn) { |
|
948 | - $filter .= '(cn=' . $cn . ')'; |
|
947 | + foreach ($cns as $cn) { |
|
948 | + $filter .= '(cn='.$cn.')'; |
|
949 | 949 | } |
950 | 950 | $filter .= ')'; |
951 | 951 | } |
952 | 952 | $parts++; |
953 | 953 | //wrap parts in AND condition |
954 | - if($parts > 1) { |
|
955 | - $filter = '(&' . $filter . ')'; |
|
954 | + if ($parts > 1) { |
|
955 | + $filter = '(&'.$filter.')'; |
|
956 | 956 | } |
957 | 957 | break; |
958 | 958 | |
@@ -964,47 +964,47 @@ discard block |
||
964 | 964 | $userAttributes = array_change_key_case(array_flip($userAttributes)); |
965 | 965 | $parts = 0; |
966 | 966 | |
967 | - if($this->configuration->ldapLoginFilterUsername === '1') { |
|
967 | + if ($this->configuration->ldapLoginFilterUsername === '1') { |
|
968 | 968 | $attr = ''; |
969 | - if(isset($userAttributes['uid'])) { |
|
969 | + if (isset($userAttributes['uid'])) { |
|
970 | 970 | $attr = 'uid'; |
971 | - } else if(isset($userAttributes['samaccountname'])) { |
|
971 | + } else if (isset($userAttributes['samaccountname'])) { |
|
972 | 972 | $attr = 'samaccountname'; |
973 | - } else if(isset($userAttributes['cn'])) { |
|
973 | + } else if (isset($userAttributes['cn'])) { |
|
974 | 974 | //fallback |
975 | 975 | $attr = 'cn'; |
976 | 976 | } |
977 | 977 | if ($attr !== '') { |
978 | - $filterUsername = '(' . $attr . $loginpart . ')'; |
|
978 | + $filterUsername = '('.$attr.$loginpart.')'; |
|
979 | 979 | $parts++; |
980 | 980 | } |
981 | 981 | } |
982 | 982 | |
983 | 983 | $filterEmail = ''; |
984 | - if($this->configuration->ldapLoginFilterEmail === '1') { |
|
984 | + if ($this->configuration->ldapLoginFilterEmail === '1') { |
|
985 | 985 | $filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))'; |
986 | 986 | $parts++; |
987 | 987 | } |
988 | 988 | |
989 | 989 | $filterAttributes = ''; |
990 | 990 | $attrsToFilter = $this->configuration->ldapLoginFilterAttributes; |
991 | - if(is_array($attrsToFilter) && count($attrsToFilter) > 0) { |
|
991 | + if (is_array($attrsToFilter) && count($attrsToFilter) > 0) { |
|
992 | 992 | $filterAttributes = '(|'; |
993 | - foreach($attrsToFilter as $attribute) { |
|
994 | - $filterAttributes .= '(' . $attribute . $loginpart . ')'; |
|
993 | + foreach ($attrsToFilter as $attribute) { |
|
994 | + $filterAttributes .= '('.$attribute.$loginpart.')'; |
|
995 | 995 | } |
996 | 996 | $filterAttributes .= ')'; |
997 | 997 | $parts++; |
998 | 998 | } |
999 | 999 | |
1000 | 1000 | $filterLogin = ''; |
1001 | - if($parts > 1) { |
|
1001 | + if ($parts > 1) { |
|
1002 | 1002 | $filterLogin = '(|'; |
1003 | 1003 | } |
1004 | 1004 | $filterLogin .= $filterUsername; |
1005 | 1005 | $filterLogin .= $filterEmail; |
1006 | 1006 | $filterLogin .= $filterAttributes; |
1007 | - if($parts > 1) { |
|
1007 | + if ($parts > 1) { |
|
1008 | 1008 | $filterLogin .= ')'; |
1009 | 1009 | } |
1010 | 1010 | |
@@ -1026,7 +1026,7 @@ discard block |
||
1026 | 1026 | * @throws \Exception |
1027 | 1027 | */ |
1028 | 1028 | private function connectAndBind($port = 389, $tls = false, $ncc = false) { |
1029 | - if($ncc) { |
|
1029 | + if ($ncc) { |
|
1030 | 1030 | //No certificate check |
1031 | 1031 | //FIXME: undo afterwards |
1032 | 1032 | putenv('LDAPTLS_REQCERT=never'); |
@@ -1036,12 +1036,12 @@ discard block |
||
1036 | 1036 | \OCP\Util::writeLog('user_ldap', 'Wiz: Checking Host Info ', \OCP\Util::DEBUG); |
1037 | 1037 | $host = $this->configuration->ldapHost; |
1038 | 1038 | $hostInfo = parse_url($host); |
1039 | - if(!$hostInfo) { |
|
1039 | + if (!$hostInfo) { |
|
1040 | 1040 | throw new \Exception(self::$l->t('Invalid Host')); |
1041 | 1041 | } |
1042 | 1042 | \OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG); |
1043 | 1043 | $cr = $this->ldap->connect($host, $port); |
1044 | - if(!is_resource($cr)) { |
|
1044 | + if (!is_resource($cr)) { |
|
1045 | 1045 | throw new \Exception(self::$l->t('Invalid Host')); |
1046 | 1046 | } |
1047 | 1047 | |
@@ -1052,9 +1052,9 @@ discard block |
||
1052 | 1052 | $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); |
1053 | 1053 | |
1054 | 1054 | try { |
1055 | - if($tls) { |
|
1055 | + if ($tls) { |
|
1056 | 1056 | $isTlsWorking = @$this->ldap->startTls($cr); |
1057 | - if(!$isTlsWorking) { |
|
1057 | + if (!$isTlsWorking) { |
|
1058 | 1058 | return false; |
1059 | 1059 | } |
1060 | 1060 | } |
@@ -1068,20 +1068,20 @@ discard block |
||
1068 | 1068 | $errNo = $this->ldap->errno($cr); |
1069 | 1069 | $error = ldap_error($cr); |
1070 | 1070 | $this->ldap->unbind($cr); |
1071 | - } catch(ServerNotAvailableException $e) { |
|
1071 | + } catch (ServerNotAvailableException $e) { |
|
1072 | 1072 | return false; |
1073 | 1073 | } |
1074 | 1074 | |
1075 | - if($login === true) { |
|
1075 | + if ($login === true) { |
|
1076 | 1076 | $this->ldap->unbind($cr); |
1077 | - if($ncc) { |
|
1077 | + if ($ncc) { |
|
1078 | 1078 | throw new \Exception('Certificate cannot be validated.'); |
1079 | 1079 | } |
1080 | - \OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . intval($tls), \OCP\Util::DEBUG); |
|
1080 | + \OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '.$port.' TLS '.intval($tls), \OCP\Util::DEBUG); |
|
1081 | 1081 | return true; |
1082 | 1082 | } |
1083 | 1083 | |
1084 | - if($errNo === -1 || ($errNo === 2 && $ncc)) { |
|
1084 | + if ($errNo === -1 || ($errNo === 2 && $ncc)) { |
|
1085 | 1085 | //host, port or TLS wrong |
1086 | 1086 | return false; |
1087 | 1087 | } else if ($errNo === 2) { |
@@ -1111,9 +1111,9 @@ discard block |
||
1111 | 1111 | */ |
1112 | 1112 | private function checkRequirements($reqs) { |
1113 | 1113 | $this->checkAgentRequirements(); |
1114 | - foreach($reqs as $option) { |
|
1114 | + foreach ($reqs as $option) { |
|
1115 | 1115 | $value = $this->configuration->$option; |
1116 | - if(empty($value)) { |
|
1116 | + if (empty($value)) { |
|
1117 | 1117 | return false; |
1118 | 1118 | } |
1119 | 1119 | } |
@@ -1135,33 +1135,33 @@ discard block |
||
1135 | 1135 | $dnRead = array(); |
1136 | 1136 | $foundItems = array(); |
1137 | 1137 | $maxEntries = 0; |
1138 | - if(!is_array($this->configuration->ldapBase) |
|
1138 | + if (!is_array($this->configuration->ldapBase) |
|
1139 | 1139 | || !isset($this->configuration->ldapBase[0])) { |
1140 | 1140 | return false; |
1141 | 1141 | } |
1142 | 1142 | $base = $this->configuration->ldapBase[0]; |
1143 | 1143 | $cr = $this->getConnection(); |
1144 | - if(!$this->ldap->isResource($cr)) { |
|
1144 | + if (!$this->ldap->isResource($cr)) { |
|
1145 | 1145 | return false; |
1146 | 1146 | } |
1147 | 1147 | $lastFilter = null; |
1148 | - if(isset($filters[count($filters)-1])) { |
|
1149 | - $lastFilter = $filters[count($filters)-1]; |
|
1148 | + if (isset($filters[count($filters) - 1])) { |
|
1149 | + $lastFilter = $filters[count($filters) - 1]; |
|
1150 | 1150 | } |
1151 | - foreach($filters as $filter) { |
|
1152 | - if($lastFilter === $filter && count($foundItems) > 0) { |
|
1151 | + foreach ($filters as $filter) { |
|
1152 | + if ($lastFilter === $filter && count($foundItems) > 0) { |
|
1153 | 1153 | //skip when the filter is a wildcard and results were found |
1154 | 1154 | continue; |
1155 | 1155 | } |
1156 | 1156 | // 20k limit for performance and reason |
1157 | 1157 | $rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000); |
1158 | - if(!$this->ldap->isResource($rr)) { |
|
1158 | + if (!$this->ldap->isResource($rr)) { |
|
1159 | 1159 | continue; |
1160 | 1160 | } |
1161 | 1161 | $entries = $this->ldap->countEntries($cr, $rr); |
1162 | 1162 | $getEntryFunc = 'firstEntry'; |
1163 | - if(($entries !== false) && ($entries > 0)) { |
|
1164 | - if(!is_null($maxF) && $entries > $maxEntries) { |
|
1163 | + if (($entries !== false) && ($entries > 0)) { |
|
1164 | + if (!is_null($maxF) && $entries > $maxEntries) { |
|
1165 | 1165 | $maxEntries = $entries; |
1166 | 1166 | $maxF = $filter; |
1167 | 1167 | } |
@@ -1169,13 +1169,13 @@ discard block |
||
1169 | 1169 | do { |
1170 | 1170 | $entry = $this->ldap->$getEntryFunc($cr, $rr); |
1171 | 1171 | $getEntryFunc = 'nextEntry'; |
1172 | - if(!$this->ldap->isResource($entry)) { |
|
1172 | + if (!$this->ldap->isResource($entry)) { |
|
1173 | 1173 | continue 2; |
1174 | 1174 | } |
1175 | 1175 | $rr = $entry; //will be expected by nextEntry next round |
1176 | 1176 | $attributes = $this->ldap->getAttributes($cr, $entry); |
1177 | 1177 | $dn = $this->ldap->getDN($cr, $entry); |
1178 | - if($dn === false || in_array($dn, $dnRead)) { |
|
1178 | + if ($dn === false || in_array($dn, $dnRead)) { |
|
1179 | 1179 | continue; |
1180 | 1180 | } |
1181 | 1181 | $newItems = array(); |
@@ -1186,7 +1186,7 @@ discard block |
||
1186 | 1186 | $foundItems = array_merge($foundItems, $newItems); |
1187 | 1187 | $this->resultCache[$dn][$attr] = $newItems; |
1188 | 1188 | $dnRead[] = $dn; |
1189 | - } while(($state === self::LRESULT_PROCESSED_SKIP |
|
1189 | + } while (($state === self::LRESULT_PROCESSED_SKIP |
|
1190 | 1190 | || $this->ldap->isResource($entry)) |
1191 | 1191 | && ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit)); |
1192 | 1192 | } |
@@ -1209,11 +1209,11 @@ discard block |
||
1209 | 1209 | */ |
1210 | 1210 | private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) { |
1211 | 1211 | $cr = $this->getConnection(); |
1212 | - if(!$cr) { |
|
1212 | + if (!$cr) { |
|
1213 | 1213 | throw new \Exception('Could not connect to LDAP'); |
1214 | 1214 | } |
1215 | 1215 | $p = 'objectclass='; |
1216 | - foreach($objectclasses as $key => $value) { |
|
1216 | + foreach ($objectclasses as $key => $value) { |
|
1217 | 1217 | $objectclasses[$key] = $p.$value; |
1218 | 1218 | } |
1219 | 1219 | $maxEntryObjC = ''; |
@@ -1225,7 +1225,7 @@ discard block |
||
1225 | 1225 | $availableFeatures = |
1226 | 1226 | $this->cumulativeSearchOnAttribute($objectclasses, $attr, |
1227 | 1227 | $dig, $maxEntryObjC); |
1228 | - if(is_array($availableFeatures) |
|
1228 | + if (is_array($availableFeatures) |
|
1229 | 1229 | && count($availableFeatures) > 0) { |
1230 | 1230 | natcasesort($availableFeatures); |
1231 | 1231 | //natcasesort keeps indices, but we must get rid of them for proper |
@@ -1236,7 +1236,7 @@ discard block |
||
1236 | 1236 | } |
1237 | 1237 | |
1238 | 1238 | $setFeatures = $this->configuration->$confkey; |
1239 | - if(is_array($setFeatures) && !empty($setFeatures)) { |
|
1239 | + if (is_array($setFeatures) && !empty($setFeatures)) { |
|
1240 | 1240 | //something is already configured? pre-select it. |
1241 | 1241 | $this->result->addChange($dbkey, $setFeatures); |
1242 | 1242 | } else if ($po && $maxEntryObjC !== '') { |
@@ -1258,7 +1258,7 @@ discard block |
||
1258 | 1258 | * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP |
1259 | 1259 | */ |
1260 | 1260 | private function getAttributeValuesFromEntry($result, $attribute, &$known) { |
1261 | - if(!is_array($result) |
|
1261 | + if (!is_array($result) |
|
1262 | 1262 | || !isset($result['count']) |
1263 | 1263 | || !$result['count'] > 0) { |
1264 | 1264 | return self::LRESULT_PROCESSED_INVALID; |
@@ -1267,12 +1267,12 @@ discard block |
||
1267 | 1267 | // strtolower on all keys for proper comparison |
1268 | 1268 | $result = \OCP\Util::mb_array_change_key_case($result); |
1269 | 1269 | $attribute = strtolower($attribute); |
1270 | - if(isset($result[$attribute])) { |
|
1271 | - foreach($result[$attribute] as $key => $val) { |
|
1272 | - if($key === 'count') { |
|
1270 | + if (isset($result[$attribute])) { |
|
1271 | + foreach ($result[$attribute] as $key => $val) { |
|
1272 | + if ($key === 'count') { |
|
1273 | 1273 | continue; |
1274 | 1274 | } |
1275 | - if(!in_array($val, $known)) { |
|
1275 | + if (!in_array($val, $known)) { |
|
1276 | 1276 | $known[] = $val; |
1277 | 1277 | } |
1278 | 1278 | } |
@@ -1286,7 +1286,7 @@ discard block |
||
1286 | 1286 | * @return bool|mixed |
1287 | 1287 | */ |
1288 | 1288 | private function getConnection() { |
1289 | - if(!is_null($this->cr)) { |
|
1289 | + if (!is_null($this->cr)) { |
|
1290 | 1290 | return $this->cr; |
1291 | 1291 | } |
1292 | 1292 | |
@@ -1298,14 +1298,14 @@ discard block |
||
1298 | 1298 | $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); |
1299 | 1299 | $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0); |
1300 | 1300 | $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); |
1301 | - if($this->configuration->ldapTLS === 1) { |
|
1301 | + if ($this->configuration->ldapTLS === 1) { |
|
1302 | 1302 | $this->ldap->startTls($cr); |
1303 | 1303 | } |
1304 | 1304 | |
1305 | 1305 | $lo = @$this->ldap->bind($cr, |
1306 | 1306 | $this->configuration->ldapAgentName, |
1307 | 1307 | $this->configuration->ldapAgentPassword); |
1308 | - if($lo === true) { |
|
1308 | + if ($lo === true) { |
|
1309 | 1309 | $this->$cr = $cr; |
1310 | 1310 | return $cr; |
1311 | 1311 | } |
@@ -1340,14 +1340,14 @@ discard block |
||
1340 | 1340 | $portSettings = array(); |
1341 | 1341 | |
1342 | 1342 | //In case the port is already provided, we will check this first |
1343 | - if($port > 0) { |
|
1343 | + if ($port > 0) { |
|
1344 | 1344 | $hostInfo = parse_url($host); |
1345 | - if(!(is_array($hostInfo) |
|
1345 | + if (!(is_array($hostInfo) |
|
1346 | 1346 | && isset($hostInfo['scheme']) |
1347 | 1347 | && stripos($hostInfo['scheme'], 'ldaps') !== false)) { |
1348 | 1348 | $portSettings[] = array('port' => $port, 'tls' => true); |
1349 | 1349 | } |
1350 | - $portSettings[] =array('port' => $port, 'tls' => false); |
|
1350 | + $portSettings[] = array('port' => $port, 'tls' => false); |
|
1351 | 1351 | } |
1352 | 1352 | |
1353 | 1353 | //default ports |