Completed
Push — master ( ff5041...e98864 )
by
unknown
29:16
created
apps/user_ldap/lib/Wizard.php 2 patches
Indentation   +1332 added lines, -1332 removed lines patch added patch discarded remove patch
@@ -16,1336 +16,1336 @@
 block discarded – undo
16 16
 use Psr\Log\LoggerInterface;
17 17
 
18 18
 class Wizard extends LDAPUtility {
19
-	protected static ?IL10N $l = null;
20
-	protected ?\LDAP\Connection $cr = null;
21
-	protected WizardResult $result;
22
-	protected LoggerInterface $logger;
23
-
24
-	public const LRESULT_PROCESSED_OK = 2;
25
-	public const LRESULT_PROCESSED_INVALID = 3;
26
-	public const LRESULT_PROCESSED_SKIP = 4;
27
-
28
-	public const LFILTER_LOGIN = 2;
29
-	public const LFILTER_USER_LIST = 3;
30
-	public const LFILTER_GROUP_LIST = 4;
31
-
32
-	public const LFILTER_MODE_ASSISTED = 2;
33
-	public const LFILTER_MODE_RAW = 1;
34
-
35
-	public const LDAP_NW_TIMEOUT = 4;
36
-
37
-	public function __construct(
38
-		protected Configuration $configuration,
39
-		ILDAPWrapper $ldap,
40
-		protected Access $access,
41
-	) {
42
-		parent::__construct($ldap);
43
-		if (is_null(static::$l)) {
44
-			static::$l = Server::get(IL10NFactory::class)->get('user_ldap');
45
-		}
46
-		$this->result = new WizardResult();
47
-		$this->logger = Server::get(LoggerInterface::class);
48
-	}
49
-
50
-	public function __destruct() {
51
-		if ($this->result->hasChanges()) {
52
-			$this->configuration->saveConfiguration();
53
-		}
54
-	}
55
-
56
-	/**
57
-	 * counts entries in the LDAP directory
58
-	 *
59
-	 * @param string $filter the LDAP search filter
60
-	 * @param string $type a string being either 'users' or 'groups';
61
-	 * @throws \Exception
62
-	 */
63
-	public function countEntries(string $filter, string $type): int {
64
-		$reqs = ['ldapHost', 'ldapBase'];
65
-		if (!$this->configuration->usesLdapi()) {
66
-			$reqs[] = 'ldapPort';
67
-		}
68
-		if ($type === 'users') {
69
-			$reqs[] = 'ldapUserFilter';
70
-		}
71
-		if (!$this->checkRequirements($reqs)) {
72
-			throw new \Exception('Requirements not met', 400);
73
-		}
74
-
75
-		$attr = ['dn']; // default
76
-		$limit = 1001;
77
-		if ($type === 'groups') {
78
-			$result = $this->access->countGroups($filter, $attr, $limit);
79
-		} elseif ($type === 'users') {
80
-			$result = $this->access->countUsers($filter, $attr, $limit);
81
-		} elseif ($type === 'objects') {
82
-			$result = $this->access->countObjects($limit);
83
-		} else {
84
-			throw new \Exception('Internal error: Invalid object type', 500);
85
-		}
86
-
87
-		return (int)$result;
88
-	}
89
-
90
-	/**
91
-	 * @return WizardResult|false
92
-	 */
93
-	public function countGroups() {
94
-		$filter = $this->configuration->ldapGroupFilter;
95
-
96
-		if (empty($filter)) {
97
-			$output = self::$l->n('%n group found', '%n groups found', 0);
98
-			$this->result->addChange('ldap_group_count', $output);
99
-			return $this->result;
100
-		}
101
-
102
-		try {
103
-			$groupsTotal = $this->countEntries($filter, 'groups');
104
-		} catch (\Exception $e) {
105
-			//400 can be ignored, 500 is forwarded
106
-			if ($e->getCode() === 500) {
107
-				throw $e;
108
-			}
109
-			return false;
110
-		}
111
-
112
-		if ($groupsTotal > 1000) {
113
-			$output = self::$l->t('> 1000 groups found');
114
-		} else {
115
-			$output = self::$l->n(
116
-				'%n group found',
117
-				'%n groups found',
118
-				$groupsTotal
119
-			);
120
-		}
121
-		$this->result->addChange('ldap_group_count', $output);
122
-		return $this->result;
123
-	}
124
-
125
-	/**
126
-	 * @throws \Exception
127
-	 */
128
-	public function countUsers(): WizardResult {
129
-		$filter = $this->access->getFilterForUserCount();
130
-
131
-		$usersTotal = $this->countEntries($filter, 'users');
132
-		if ($usersTotal > 1000) {
133
-			$output = self::$l->t('> 1000 users found');
134
-		} else {
135
-			$output = self::$l->n(
136
-				'%n user found',
137
-				'%n users found',
138
-				$usersTotal
139
-			);
140
-		}
141
-		$this->result->addChange('ldap_user_count', $output);
142
-		return $this->result;
143
-	}
144
-
145
-	/**
146
-	 * counts any objects in the currently set base dn
147
-	 *
148
-	 * @throws \Exception
149
-	 */
150
-	public function countInBaseDN(): WizardResult {
151
-		// we don't need to provide a filter in this case
152
-		$total = $this->countEntries('', 'objects');
153
-		$this->result->addChange('ldap_test_base', $total);
154
-		return $this->result;
155
-	}
156
-
157
-	/**
158
-	 * counts users with a specified attribute
159
-	 * @return int|false
160
-	 */
161
-	public function countUsersWithAttribute(string $attr, bool $existsCheck = false) {
162
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
163
-		if (!$this->configuration->usesLdapi()) {
164
-			$reqs[] = 'ldapPort';
165
-		}
166
-		if (!$this->checkRequirements($reqs)) {
167
-			return  false;
168
-		}
169
-
170
-		$filter = $this->access->combineFilterWithAnd([
171
-			$this->configuration->ldapUserFilter,
172
-			$attr . '=*'
173
-		]);
174
-
175
-		$limit = $existsCheck ? null : 1;
176
-
177
-		return $this->access->countUsers($filter, ['dn'], $limit);
178
-	}
179
-
180
-	/**
181
-	 * detects the display name attribute. If a setting is already present that
182
-	 * returns at least one hit, the detection will be canceled.
183
-	 * @return WizardResult|false
184
-	 * @throws \Exception
185
-	 */
186
-	public function detectUserDisplayNameAttribute() {
187
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
188
-		if (!$this->configuration->usesLdapi()) {
189
-			$reqs[] = 'ldapPort';
190
-		}
191
-		if (!$this->checkRequirements($reqs)) {
192
-			return  false;
193
-		}
194
-
195
-		$attr = $this->configuration->ldapUserDisplayName;
196
-		if ($attr !== '' && $attr !== 'displayName') {
197
-			// most likely not the default value with upper case N,
198
-			// verify it still produces a result
199
-			$count = (int)$this->countUsersWithAttribute($attr, true);
200
-			if ($count > 0) {
201
-				//no change, but we sent it back to make sure the user interface
202
-				//is still correct, even if the call was cancelled meanwhile
203
-				$this->result->addChange('ldap_display_name', $attr);
204
-				return $this->result;
205
-			}
206
-		}
207
-
208
-		// first attribute that has at least one result wins
209
-		$displayNameAttrs = ['displayname', 'cn'];
210
-		foreach ($displayNameAttrs as $attr) {
211
-			$count = (int)$this->countUsersWithAttribute($attr, true);
212
-
213
-			if ($count > 0) {
214
-				$this->applyFind('ldap_display_name', $attr);
215
-				return $this->result;
216
-			}
217
-		}
218
-
219
-		throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced LDAP settings.'));
220
-	}
221
-
222
-	/**
223
-	 * detects the most often used email attribute for users applying to the
224
-	 * user list filter. If a setting is already present that returns at least
225
-	 * one hit, the detection will be canceled.
226
-	 * @return WizardResult|bool
227
-	 */
228
-	public function detectEmailAttribute() {
229
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
230
-		if (!$this->configuration->usesLdapi()) {
231
-			$reqs[] = 'ldapPort';
232
-		}
233
-		if (!$this->checkRequirements($reqs)) {
234
-			return  false;
235
-		}
236
-
237
-		$attr = $this->configuration->ldapEmailAttribute;
238
-		if ($attr !== '') {
239
-			$count = (int)$this->countUsersWithAttribute($attr, true);
240
-			if ($count > 0) {
241
-				return false;
242
-			}
243
-			$writeLog = true;
244
-		} else {
245
-			$writeLog = false;
246
-		}
247
-
248
-		$emailAttributes = ['mail', 'mailPrimaryAddress'];
249
-		$winner = '';
250
-		$maxUsers = 0;
251
-		foreach ($emailAttributes as $attr) {
252
-			$count = $this->countUsersWithAttribute($attr);
253
-			if ($count > $maxUsers) {
254
-				$maxUsers = $count;
255
-				$winner = $attr;
256
-			}
257
-		}
258
-
259
-		if ($winner !== '') {
260
-			$this->applyFind('ldap_email_attr', $winner);
261
-			if ($writeLog) {
262
-				$this->logger->info(
263
-					'The mail attribute has automatically been reset, '
264
-					. 'because the original value did not return any results.',
265
-					['app' => 'user_ldap']
266
-				);
267
-			}
268
-		}
269
-
270
-		return $this->result;
271
-	}
272
-
273
-	/**
274
-	 * @return WizardResult|false
275
-	 * @throws \Exception
276
-	 */
277
-	public function determineAttributes() {
278
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
279
-		if (!$this->configuration->usesLdapi()) {
280
-			$reqs[] = 'ldapPort';
281
-		}
282
-		if (!$this->checkRequirements($reqs)) {
283
-			return  false;
284
-		}
285
-
286
-		$attributes = $this->getUserAttributes();
287
-
288
-		if (!is_array($attributes)) {
289
-			throw new \Exception('Failed to determine user attributes');
290
-		}
291
-
292
-		natcasesort($attributes);
293
-		$attributes = array_values($attributes);
294
-
295
-		$this->result->addOptions('ldap_loginfilter_attributes', $attributes);
296
-
297
-		$selected = $this->configuration->ldapLoginFilterAttributes;
298
-		if (is_array($selected) && !empty($selected)) {
299
-			$this->result->addChange('ldap_loginfilter_attributes', $selected);
300
-		}
301
-
302
-		return $this->result;
303
-	}
304
-
305
-	/**
306
-	 * detects the available LDAP attributes
307
-	 * @return array|false
308
-	 * @throws \Exception
309
-	 */
310
-	private function getUserAttributes() {
311
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
312
-		if (!$this->configuration->usesLdapi()) {
313
-			$reqs[] = 'ldapPort';
314
-		}
315
-		if (!$this->checkRequirements($reqs)) {
316
-			return  false;
317
-		}
318
-		$cr = $this->getConnection();
319
-		if (!$cr) {
320
-			throw new \Exception('Could not connect to LDAP');
321
-		}
322
-
323
-		$base = $this->configuration->ldapBase[0];
324
-		$filter = $this->configuration->ldapUserFilter;
325
-		$rr = $this->ldap->search($cr, $base, $filter, [], 1, 1);
326
-		if (!$this->ldap->isResource($rr)) {
327
-			return false;
328
-		}
329
-		/** @var \LDAP\Result $rr */
330
-		$er = $this->ldap->firstEntry($cr, $rr);
331
-		$attributes = $this->ldap->getAttributes($cr, $er);
332
-		if ($attributes === false) {
333
-			return false;
334
-		}
335
-		$pureAttributes = [];
336
-		for ($i = 0; $i < $attributes['count']; $i++) {
337
-			$pureAttributes[] = $attributes[$i];
338
-		}
339
-
340
-		return $pureAttributes;
341
-	}
342
-
343
-	/**
344
-	 * detects the available LDAP groups
345
-	 * @return WizardResult|false the instance's WizardResult instance
346
-	 */
347
-	public function determineGroupsForGroups() {
348
-		return $this->determineGroups('ldap_groupfilter_groups',
349
-			'ldapGroupFilterGroups',
350
-			false);
351
-	}
352
-
353
-	/**
354
-	 * detects the available LDAP groups
355
-	 * @return WizardResult|false the instance's WizardResult instance
356
-	 */
357
-	public function determineGroupsForUsers() {
358
-		return $this->determineGroups('ldap_userfilter_groups',
359
-			'ldapUserFilterGroups');
360
-	}
361
-
362
-	/**
363
-	 * detects the available LDAP groups
364
-	 * @return WizardResult|false the instance's WizardResult instance
365
-	 * @throws \Exception
366
-	 */
367
-	private function determineGroups(string $dbKey, string $confKey, bool $testMemberOf = true) {
368
-		$reqs = ['ldapHost', 'ldapBase'];
369
-		if (!$this->configuration->usesLdapi()) {
370
-			$reqs[] = 'ldapPort';
371
-		}
372
-		if (!$this->checkRequirements($reqs)) {
373
-			return  false;
374
-		}
375
-		$cr = $this->getConnection();
376
-		if (!$cr) {
377
-			throw new \Exception('Could not connect to LDAP');
378
-		}
379
-
380
-		$this->fetchGroups($dbKey, $confKey);
381
-
382
-		if ($testMemberOf) {
383
-			$this->configuration->hasMemberOfFilterSupport = (string)$this->testMemberOf();
384
-			$this->result->markChange();
385
-			if (!$this->configuration->hasMemberOfFilterSupport) {
386
-				throw new \Exception('memberOf is not supported by the server');
387
-			}
388
-		}
389
-
390
-		return $this->result;
391
-	}
392
-
393
-	/**
394
-	 * fetches all groups from LDAP and adds them to the result object
395
-	 *
396
-	 * @throws \Exception
397
-	 */
398
-	public function fetchGroups(string $dbKey, string $confKey): array {
399
-		$obclasses = ['posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames', 'groupOfUniqueNames'];
400
-
401
-		$filterParts = [];
402
-		foreach ($obclasses as $obclass) {
403
-			$filterParts[] = 'objectclass=' . $obclass;
404
-		}
405
-		//we filter for everything
406
-		//- that looks like a group and
407
-		//- has the group display name set
408
-		$filter = $this->access->combineFilterWithOr($filterParts);
409
-		$filter = $this->access->combineFilterWithAnd([$filter, 'cn=*']);
410
-
411
-		$groupNames = [];
412
-		$groupEntries = [];
413
-		$limit = 400;
414
-		$offset = 0;
415
-		do {
416
-			// we need to request dn additionally here, otherwise memberOf
417
-			// detection will fail later
418
-			$result = $this->access->searchGroups($filter, ['cn', 'dn'], $limit, $offset);
419
-			foreach ($result as $item) {
420
-				if (!isset($item['cn']) || !is_array($item['cn']) || !isset($item['cn'][0])) {
421
-					// just in case - no issue known
422
-					continue;
423
-				}
424
-				$groupNames[] = $item['cn'][0];
425
-				$groupEntries[] = $item;
426
-			}
427
-			$offset += $limit;
428
-		} while ($this->access->hasMoreResults());
429
-
430
-		if (count($groupNames) > 0) {
431
-			natsort($groupNames);
432
-			$this->result->addOptions($dbKey, array_values($groupNames));
433
-		} else {
434
-			throw new \Exception(self::$l->t('Could not find the desired feature'));
435
-		}
436
-
437
-		$setFeatures = $this->configuration->$confKey;
438
-		if (is_array($setFeatures) && !empty($setFeatures)) {
439
-			//something is already configured? pre-select it.
440
-			$this->result->addChange($dbKey, $setFeatures);
441
-		}
442
-		return $groupEntries;
443
-	}
444
-
445
-	/**
446
-	 * @return WizardResult|false
447
-	 */
448
-	public function determineGroupMemberAssoc() {
449
-		$reqs = ['ldapHost', 'ldapGroupFilter'];
450
-		if (!$this->configuration->usesLdapi()) {
451
-			$reqs[] = 'ldapPort';
452
-		}
453
-		if (!$this->checkRequirements($reqs)) {
454
-			return  false;
455
-		}
456
-		$attribute = $this->detectGroupMemberAssoc();
457
-		if ($attribute === false) {
458
-			return false;
459
-		}
460
-		$this->configuration->setConfiguration(['ldapGroupMemberAssocAttr' => $attribute]);
461
-		$this->result->addChange('ldap_group_member_assoc_attribute', $attribute);
462
-
463
-		return $this->result;
464
-	}
465
-
466
-	/**
467
-	 * Detects the available object classes
468
-	 * @return WizardResult|false the instance's WizardResult instance
469
-	 * @throws \Exception
470
-	 */
471
-	public function determineGroupObjectClasses() {
472
-		$reqs = ['ldapHost', 'ldapBase'];
473
-		if (!$this->configuration->usesLdapi()) {
474
-			$reqs[] = 'ldapPort';
475
-		}
476
-		if (!$this->checkRequirements($reqs)) {
477
-			return  false;
478
-		}
479
-		$cr = $this->getConnection();
480
-		if (!$cr) {
481
-			throw new \Exception('Could not connect to LDAP');
482
-		}
483
-
484
-		$obclasses = ['groupOfNames', 'groupOfUniqueNames', 'group', 'posixGroup', '*'];
485
-		$this->determineFeature($obclasses,
486
-			'objectclass',
487
-			'ldap_groupfilter_objectclass',
488
-			'ldapGroupFilterObjectclass',
489
-			false);
490
-
491
-		return $this->result;
492
-	}
493
-
494
-	/**
495
-	 * detects the available object classes
496
-	 * @return WizardResult|false
497
-	 * @throws \Exception
498
-	 */
499
-	public function determineUserObjectClasses() {
500
-		$reqs = ['ldapHost', 'ldapBase'];
501
-		if (!$this->configuration->usesLdapi()) {
502
-			$reqs[] = 'ldapPort';
503
-		}
504
-		if (!$this->checkRequirements($reqs)) {
505
-			return  false;
506
-		}
507
-		$cr = $this->getConnection();
508
-		if (!$cr) {
509
-			throw new \Exception('Could not connect to LDAP');
510
-		}
511
-
512
-		$obclasses = ['inetOrgPerson', 'person', 'organizationalPerson',
513
-			'user', 'posixAccount', '*'];
514
-		$filter = $this->configuration->ldapUserFilter;
515
-		//if filter is empty, it is probably the first time the wizard is called
516
-		//then, apply suggestions.
517
-		$this->determineFeature($obclasses,
518
-			'objectclass',
519
-			'ldap_userfilter_objectclass',
520
-			'ldapUserFilterObjectclass',
521
-			empty($filter));
522
-
523
-		return $this->result;
524
-	}
525
-
526
-	/**
527
-	 * @return WizardResult|false
528
-	 * @throws \Exception
529
-	 */
530
-	public function getGroupFilter() {
531
-		$reqs = ['ldapHost', 'ldapBase'];
532
-		if (!$this->configuration->usesLdapi()) {
533
-			$reqs[] = 'ldapPort';
534
-		}
535
-		if (!$this->checkRequirements($reqs)) {
536
-			return false;
537
-		}
538
-		//make sure the use display name is set
539
-		$displayName = $this->configuration->ldapGroupDisplayName;
540
-		if ($displayName === '') {
541
-			$d = $this->configuration->getDefaults();
542
-			$this->applyFind('ldap_group_display_name',
543
-				$d['ldap_group_display_name']);
544
-		}
545
-		$filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST);
546
-
547
-		$this->applyFind('ldap_group_filter', $filter);
548
-		return $this->result;
549
-	}
550
-
551
-	/**
552
-	 * @return WizardResult|false
553
-	 * @throws \Exception
554
-	 */
555
-	public function getUserListFilter() {
556
-		$reqs = ['ldapHost', 'ldapBase'];
557
-		if (!$this->configuration->usesLdapi()) {
558
-			$reqs[] = 'ldapPort';
559
-		}
560
-		if (!$this->checkRequirements($reqs)) {
561
-			return false;
562
-		}
563
-		//make sure the use display name is set
564
-		$displayName = $this->configuration->ldapUserDisplayName;
565
-		if ($displayName === '') {
566
-			$d = $this->configuration->getDefaults();
567
-			$this->applyFind('ldap_display_name', $d['ldap_display_name']);
568
-		}
569
-		$filter = $this->composeLdapFilter(self::LFILTER_USER_LIST);
570
-		if (!$filter) {
571
-			throw new \Exception('Cannot create filter');
572
-		}
573
-
574
-		$this->applyFind('ldap_userlist_filter', $filter);
575
-		return $this->result;
576
-	}
577
-
578
-	/**
579
-	 * @return WizardResult|false
580
-	 * @throws \Exception
581
-	 */
582
-	public function getUserLoginFilter() {
583
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
584
-		if (!$this->configuration->usesLdapi()) {
585
-			$reqs[] = 'ldapPort';
586
-		}
587
-		if (!$this->checkRequirements($reqs)) {
588
-			return false;
589
-		}
590
-
591
-		$filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
592
-		if (!$filter) {
593
-			throw new \Exception('Cannot create filter');
594
-		}
595
-
596
-		$this->applyFind('ldap_login_filter', $filter);
597
-		return $this->result;
598
-	}
599
-
600
-	/**
601
-	 * @return WizardResult|false
602
-	 * @throws \Exception
603
-	 */
604
-	public function testLoginName(string $loginName) {
605
-		$reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
606
-		if (!$this->configuration->usesLdapi()) {
607
-			$reqs[] = 'ldapPort';
608
-		}
609
-		if (!$this->checkRequirements($reqs)) {
610
-			return false;
611
-		}
612
-
613
-		$cr = $this->access->connection->getConnectionResource();
614
-
615
-		if (mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
616
-			=== false) {
617
-			throw new \Exception('missing placeholder');
618
-		}
619
-
620
-		$users = $this->access->countUsersByLoginName($loginName);
621
-		if ($this->ldap->errno($cr) !== 0) {
622
-			throw new \Exception($this->ldap->error($cr));
623
-		}
624
-		$filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
625
-		$this->result->addChange('ldap_test_loginname', $users);
626
-		$this->result->addChange('ldap_test_effective_filter', $filter);
627
-		return $this->result;
628
-	}
629
-
630
-	/**
631
-	 * Tries to determine the port, requires given Host, User DN and Password
632
-	 * @return WizardResult|false WizardResult on success, false otherwise
633
-	 * @throws \Exception
634
-	 */
635
-	public function guessPortAndTLS() {
636
-		if (!$this->checkRequirements(['ldapHost',
637
-		])) {
638
-			return false;
639
-		}
640
-		$this->checkHost();
641
-		$portSettings = $this->getPortSettingsToTry();
642
-
643
-		//proceed from the best configuration and return on first success
644
-		foreach ($portSettings as $setting) {
645
-			$p = $setting['port'];
646
-			$t = $setting['tls'];
647
-			$this->logger->debug(
648
-				'Wiz: trying port ' . $p . ', TLS ' . $t,
649
-				['app' => 'user_ldap']
650
-			);
651
-			//connectAndBind may throw Exception, it needs to be caught by the
652
-			//callee of this method
653
-
654
-			try {
655
-				$settingsFound = $this->connectAndBind($p, $t);
656
-			} catch (\Exception $e) {
657
-				// any reply other than -1 (= cannot connect) is already okay,
658
-				// because then we found the server
659
-				// unavailable startTLS returns -11
660
-				if ($e->getCode() > 0) {
661
-					$settingsFound = true;
662
-				} else {
663
-					throw $e;
664
-				}
665
-			}
666
-
667
-			if ($settingsFound === true) {
668
-				$config = [
669
-					'ldapPort' => (string)$p,
670
-					'ldapTLS' => (string)$t,
671
-				];
672
-				$this->configuration->setConfiguration($config);
673
-				$this->logger->debug(
674
-					'Wiz: detected Port ' . $p,
675
-					['app' => 'user_ldap']
676
-				);
677
-				$this->result->addChange('ldap_port', $p);
678
-				return $this->result;
679
-			}
680
-		}
681
-
682
-		//custom port, undetected (we do not brute force)
683
-		return false;
684
-	}
685
-
686
-	/**
687
-	 * tries to determine a base dn from User DN or LDAP Host
688
-	 * @return WizardResult|false WizardResult on success, false otherwise
689
-	 */
690
-	public function guessBaseDN() {
691
-		$reqs = ['ldapHost'];
692
-		if (!$this->configuration->usesLdapi()) {
693
-			$reqs[] = 'ldapPort';
694
-		}
695
-		if (!$this->checkRequirements($reqs)) {
696
-			return false;
697
-		}
698
-
699
-		//check whether a DN is given in the agent name (99.9% of all cases)
700
-		$base = null;
701
-		$i = stripos($this->configuration->ldapAgentName, 'dc=');
702
-		if ($i !== false) {
703
-			$base = substr($this->configuration->ldapAgentName, $i);
704
-			if ($this->testBaseDN($base)) {
705
-				$this->applyFind('ldap_base', $base);
706
-				return $this->result;
707
-			}
708
-		}
709
-
710
-		//this did not help :(
711
-		//Let's see whether we can parse the Host URL and convert the domain to
712
-		//a base DN
713
-		$helper = Server::get(Helper::class);
714
-		$domain = $helper->getDomainFromURL($this->configuration->ldapHost);
715
-		if (!$domain) {
716
-			return false;
717
-		}
718
-
719
-		$dparts = explode('.', $domain);
720
-		while (count($dparts) > 0) {
721
-			$base2 = 'dc=' . implode(',dc=', $dparts);
722
-			if ($base !== $base2 && $this->testBaseDN($base2)) {
723
-				$this->applyFind('ldap_base', $base2);
724
-				return $this->result;
725
-			}
726
-			array_shift($dparts);
727
-		}
728
-
729
-		return false;
730
-	}
731
-
732
-	/**
733
-	 * sets the found value for the configuration key in the WizardResult
734
-	 * as well as in the Configuration instance
735
-	 * @param string $key the configuration key
736
-	 * @param string $value the (detected) value
737
-	 *
738
-	 */
739
-	private function applyFind(string $key, string $value): void {
740
-		$this->result->addChange($key, $value);
741
-		$this->configuration->setConfiguration([$key => $value]);
742
-	}
743
-
744
-	/**
745
-	 * Checks, whether a port was entered in the Host configuration
746
-	 * field. In this case the port will be stripped off, but also stored as
747
-	 * setting.
748
-	 */
749
-	private function checkHost(): void {
750
-		$host = $this->configuration->ldapHost;
751
-		$hostInfo = parse_url($host);
752
-
753
-		//removes Port from Host
754
-		if (is_array($hostInfo) && isset($hostInfo['port'])) {
755
-			$port = $hostInfo['port'];
756
-			$host = str_replace(':' . $port, '', $host);
757
-			$this->applyFind('ldap_host', $host);
758
-			$this->applyFind('ldap_port', (string)$port);
759
-		}
760
-	}
761
-
762
-	/**
763
-	 * tries to detect the group member association attribute which is
764
-	 * one of 'uniqueMember', 'memberUid', 'member', 'gidNumber'
765
-	 * @return string|false string with the attribute name, false on error
766
-	 * @throws \Exception
767
-	 */
768
-	private function detectGroupMemberAssoc() {
769
-		$possibleAttrs = ['uniqueMember', 'memberUid', 'member', 'gidNumber', 'zimbraMailForwardingAddress'];
770
-		$filter = $this->configuration->ldapGroupFilter;
771
-		if (empty($filter)) {
772
-			return false;
773
-		}
774
-		$cr = $this->getConnection();
775
-		if (!$cr) {
776
-			throw new \Exception('Could not connect to LDAP');
777
-		}
778
-		$base = $this->configuration->ldapBaseGroups[0] ?: $this->configuration->ldapBase[0];
779
-		$rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000);
780
-		if (!$this->ldap->isResource($rr)) {
781
-			return false;
782
-		}
783
-		/** @var \LDAP\Result $rr */
784
-		$er = $this->ldap->firstEntry($cr, $rr);
785
-		while ($this->ldap->isResource($er)) {
786
-			$this->ldap->getDN($cr, $er);
787
-			$attrs = $this->ldap->getAttributes($cr, $er);
788
-			$result = [];
789
-			$possibleAttrsCount = count($possibleAttrs);
790
-			for ($i = 0; $i < $possibleAttrsCount; $i++) {
791
-				if (isset($attrs[$possibleAttrs[$i]])) {
792
-					$result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count'];
793
-				}
794
-			}
795
-			if (!empty($result)) {
796
-				natsort($result);
797
-				return key($result);
798
-			}
799
-
800
-			$er = $this->ldap->nextEntry($cr, $er);
801
-		}
802
-
803
-		return false;
804
-	}
805
-
806
-	/**
807
-	 * Checks whether for a given BaseDN results will be returned
808
-	 * @param string $base the BaseDN to test
809
-	 * @return bool true on success, false otherwise
810
-	 * @throws \Exception
811
-	 */
812
-	private function testBaseDN(string $base): bool {
813
-		$cr = $this->getConnection();
814
-		if (!$cr) {
815
-			throw new \Exception('Could not connect to LDAP');
816
-		}
817
-
818
-		//base is there, let's validate it. If we search for anything, we should
819
-		//get a result set > 0 on a proper base
820
-		$rr = $this->ldap->search($cr, $base, 'objectClass=*', ['dn'], 0, 1);
821
-		if (!$this->ldap->isResource($rr)) {
822
-			$errorNo = $this->ldap->errno($cr);
823
-			$errorMsg = $this->ldap->error($cr);
824
-			$this->logger->info(
825
-				'Wiz: Could not search base ' . $base . ' Error ' . $errorNo . ': ' . $errorMsg,
826
-				['app' => 'user_ldap']
827
-			);
828
-			return false;
829
-		}
830
-		/** @var \LDAP\Result $rr */
831
-		$entries = $this->ldap->countEntries($cr, $rr);
832
-		return ($entries !== false) && ($entries > 0);
833
-	}
834
-
835
-	/**
836
-	 * Checks whether the server supports memberOf in LDAP Filter.
837
-	 * Note: at least in OpenLDAP, availability of memberOf is dependent on
838
-	 * a configured objectClass. I.e. not necessarily for all available groups
839
-	 * memberOf does work.
840
-	 *
841
-	 * @return bool true if it does, false otherwise
842
-	 * @throws \Exception
843
-	 */
844
-	private function testMemberOf(): bool {
845
-		$cr = $this->getConnection();
846
-		if (!$cr) {
847
-			throw new \Exception('Could not connect to LDAP');
848
-		}
849
-		$result = $this->access->countUsers('memberOf=*', ['memberOf'], 1);
850
-		if (is_int($result) && $result > 0) {
851
-			return true;
852
-		}
853
-		return false;
854
-	}
855
-
856
-	/**
857
-	 * creates an LDAP Filter from given configuration
858
-	 * @param int $filterType int, for which use case the filter shall be created
859
-	 *                        can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or
860
-	 *                        self::LFILTER_GROUP_LIST
861
-	 * @throws \Exception
862
-	 */
863
-	private function composeLdapFilter(int $filterType): string {
864
-		$filter = '';
865
-		$parts = 0;
866
-		switch ($filterType) {
867
-			case self::LFILTER_USER_LIST:
868
-				$objcs = $this->configuration->ldapUserFilterObjectclass;
869
-				//glue objectclasses
870
-				if (is_array($objcs) && count($objcs) > 0) {
871
-					$filter .= '(|';
872
-					foreach ($objcs as $objc) {
873
-						$filter .= '(objectclass=' . ldap_escape($objc, '', LDAP_ESCAPE_FILTER) . ')';
874
-					}
875
-					$filter .= ')';
876
-					$parts++;
877
-				}
878
-				//glue group memberships
879
-				if ($this->configuration->hasMemberOfFilterSupport) {
880
-					$cns = $this->configuration->ldapUserFilterGroups;
881
-					if (is_array($cns) && count($cns) > 0) {
882
-						$filter .= '(|';
883
-						$cr = $this->getConnection();
884
-						if (!$cr) {
885
-							throw new \Exception('Could not connect to LDAP');
886
-						}
887
-						$base = $this->configuration->ldapBase[0];
888
-						foreach ($cns as $cn) {
889
-							$rr = $this->ldap->search($cr, $base, 'cn=' . ldap_escape($cn, '', LDAP_ESCAPE_FILTER), ['dn', 'primaryGroupToken']);
890
-							if (!$this->ldap->isResource($rr)) {
891
-								continue;
892
-							}
893
-							/** @var \LDAP\Result $rr */
894
-							$er = $this->ldap->firstEntry($cr, $rr);
895
-							$attrs = $this->ldap->getAttributes($cr, $er);
896
-							$dn = $this->ldap->getDN($cr, $er);
897
-							if ($dn === false || $dn === '') {
898
-								continue;
899
-							}
900
-							$filterPart = '(memberof=' . ldap_escape($dn, '', LDAP_ESCAPE_FILTER) . ')';
901
-							if (isset($attrs['primaryGroupToken'])) {
902
-								$pgt = $attrs['primaryGroupToken'][0];
903
-								$primaryFilterPart = '(primaryGroupID=' . ldap_escape($pgt, '', LDAP_ESCAPE_FILTER) . ')';
904
-								$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
905
-							}
906
-							$filter .= $filterPart;
907
-						}
908
-						$filter .= ')';
909
-					}
910
-					$parts++;
911
-				}
912
-				//wrap parts in AND condition
913
-				if ($parts > 1) {
914
-					$filter = '(&' . $filter . ')';
915
-				}
916
-				if ($filter === '') {
917
-					$filter = '(objectclass=*)';
918
-				}
919
-				break;
920
-
921
-			case self::LFILTER_GROUP_LIST:
922
-				$objcs = $this->configuration->ldapGroupFilterObjectclass;
923
-				//glue objectclasses
924
-				if (is_array($objcs) && count($objcs) > 0) {
925
-					$filter .= '(|';
926
-					foreach ($objcs as $objc) {
927
-						$filter .= '(objectclass=' . ldap_escape($objc, '', LDAP_ESCAPE_FILTER) . ')';
928
-					}
929
-					$filter .= ')';
930
-					$parts++;
931
-				}
932
-				//glue group memberships
933
-				$cns = $this->configuration->ldapGroupFilterGroups;
934
-				if (is_array($cns) && count($cns) > 0) {
935
-					$filter .= '(|';
936
-					foreach ($cns as $cn) {
937
-						$filter .= '(cn=' . ldap_escape($cn, '', LDAP_ESCAPE_FILTER) . ')';
938
-					}
939
-					$filter .= ')';
940
-				}
941
-				$parts++;
942
-				//wrap parts in AND condition
943
-				if ($parts > 1) {
944
-					$filter = '(&' . $filter . ')';
945
-				}
946
-				break;
947
-
948
-			case self::LFILTER_LOGIN:
949
-				$ulf = $this->configuration->ldapUserFilter;
950
-				$loginpart = '=%uid';
951
-				$filterUsername = '';
952
-				$userAttributes = $this->getUserAttributes();
953
-				if ($userAttributes === false) {
954
-					throw new \Exception('Failed to get user attributes');
955
-				}
956
-				$userAttributes = array_change_key_case(array_flip($userAttributes));
957
-				$parts = 0;
958
-
959
-				if ($this->configuration->ldapLoginFilterUsername === '1') {
960
-					$attr = '';
961
-					if (isset($userAttributes['uid'])) {
962
-						$attr = 'uid';
963
-					} elseif (isset($userAttributes['samaccountname'])) {
964
-						$attr = 'samaccountname';
965
-					} elseif (isset($userAttributes['cn'])) {
966
-						//fallback
967
-						$attr = 'cn';
968
-					}
969
-					if ($attr !== '') {
970
-						$filterUsername = '(' . $attr . $loginpart . ')';
971
-						$parts++;
972
-					}
973
-				}
974
-
975
-				$filterEmail = '';
976
-				if ($this->configuration->ldapLoginFilterEmail === '1') {
977
-					$filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))';
978
-					$parts++;
979
-				}
980
-
981
-				$filterAttributes = '';
982
-				$attrsToFilter = $this->configuration->ldapLoginFilterAttributes;
983
-				if (is_array($attrsToFilter) && count($attrsToFilter) > 0) {
984
-					$filterAttributes = '(|';
985
-					foreach ($attrsToFilter as $attribute) {
986
-						$filterAttributes .= '(' . $attribute . $loginpart . ')';
987
-					}
988
-					$filterAttributes .= ')';
989
-					$parts++;
990
-				}
991
-
992
-				$filterLogin = '';
993
-				if ($parts > 1) {
994
-					$filterLogin = '(|';
995
-				}
996
-				$filterLogin .= $filterUsername;
997
-				$filterLogin .= $filterEmail;
998
-				$filterLogin .= $filterAttributes;
999
-				if ($parts > 1) {
1000
-					$filterLogin .= ')';
1001
-				}
1002
-
1003
-				$filter = '(&' . $ulf . $filterLogin . ')';
1004
-				break;
1005
-		}
1006
-
1007
-		$this->logger->debug(
1008
-			'Wiz: Final filter ' . $filter,
1009
-			['app' => 'user_ldap']
1010
-		);
1011
-
1012
-		return $filter;
1013
-	}
1014
-
1015
-	/**
1016
-	 * Connects and Binds to an LDAP Server
1017
-	 *
1018
-	 * @param int $port the port to connect with
1019
-	 * @param bool $tls whether startTLS is to be used
1020
-	 * @throws \Exception
1021
-	 */
1022
-	private function connectAndBind(int $port, bool $tls): bool {
1023
-		//connect, does not really trigger any server communication
1024
-		$host = $this->configuration->ldapHost;
1025
-		$hostInfo = parse_url((string)$host);
1026
-		if (!is_string($host) || !$hostInfo) {
1027
-			throw new \Exception(self::$l->t('Invalid Host'));
1028
-		}
1029
-		$this->logger->debug(
1030
-			'Wiz: Attempting to connect',
1031
-			['app' => 'user_ldap']
1032
-		);
1033
-		$cr = $this->ldap->connect($host, (string)$port);
1034
-		if (!$this->ldap->isResource($cr)) {
1035
-			throw new \Exception(self::$l->t('Invalid Host'));
1036
-		}
1037
-		/** @var \LDAP\Connection $cr */
1038
-
1039
-		//set LDAP options
1040
-		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1041
-		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1042
-		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1043
-
1044
-		try {
1045
-			if ($tls) {
1046
-				$isTlsWorking = @$this->ldap->startTls($cr);
1047
-				if (!$isTlsWorking) {
1048
-					return false;
1049
-				}
1050
-			}
1051
-
1052
-			$this->logger->debug(
1053
-				'Wiz: Attempting to Bind',
1054
-				['app' => 'user_ldap']
1055
-			);
1056
-			//interesting part: do the bind!
1057
-			$login = $this->ldap->bind($cr,
1058
-				$this->configuration->ldapAgentName,
1059
-				$this->configuration->ldapAgentPassword
1060
-			);
1061
-			$errNo = $this->ldap->errno($cr);
1062
-			$error = $this->ldap->error($cr);
1063
-			$this->ldap->unbind($cr);
1064
-		} catch (ServerNotAvailableException $e) {
1065
-			return false;
1066
-		}
1067
-
1068
-		if ($login === true) {
1069
-			$this->logger->debug(
1070
-				'Wiz: Bind successful to Port ' . $port . ' TLS ' . (int)$tls,
1071
-				['app' => 'user_ldap']
1072
-			);
1073
-			return true;
1074
-		}
1075
-
1076
-		if ($errNo === -1) {
1077
-			//host, port or TLS wrong
1078
-			return false;
1079
-		}
1080
-		throw new \Exception($error, $errNo);
1081
-	}
1082
-
1083
-	/**
1084
-	 * checks whether a valid combination of agent and password has been
1085
-	 * provided (either two values or nothing for anonymous connect)
1086
-	 * @return bool true if everything is fine, false otherwise
1087
-	 */
1088
-	private function checkAgentRequirements(): bool {
1089
-		$agent = $this->configuration->ldapAgentName;
1090
-		$pwd = $this->configuration->ldapAgentPassword;
1091
-
1092
-		return
1093
-			($agent !== '' && $pwd !== '')
1094
-			|| ($agent === '' && $pwd === '')
1095
-		;
1096
-	}
1097
-
1098
-	private function checkRequirements(array $reqs): bool {
1099
-		$this->checkAgentRequirements();
1100
-		foreach ($reqs as $option) {
1101
-			$value = $this->configuration->$option;
1102
-			if (empty($value)) {
1103
-				return false;
1104
-			}
1105
-		}
1106
-		return true;
1107
-	}
1108
-
1109
-	/**
1110
-	 * does a cumulativeSearch on LDAP to get different values of a
1111
-	 * specified attribute
1112
-	 * @param string[] $filters array, the filters that shall be used in the search
1113
-	 * @param string $attr the attribute of which a list of values shall be returned
1114
-	 * @param int $dnReadLimit the amount of how many DNs should be analyzed.
1115
-	 *                         The lower, the faster
1116
-	 * @param string $maxF string. if not null, this variable will have the filter that
1117
-	 *                     yields most result entries
1118
-	 * @return array|false an array with the values on success, false otherwise
1119
-	 */
1120
-	public function cumulativeSearchOnAttribute(array $filters, string $attr, int $dnReadLimit = 3, ?string &$maxF = null) {
1121
-		$dnRead = [];
1122
-		$foundItems = [];
1123
-		$maxEntries = 0;
1124
-		if (!is_array($this->configuration->ldapBase)
1125
-		   || !isset($this->configuration->ldapBase[0])) {
1126
-			return false;
1127
-		}
1128
-		$base = $this->configuration->ldapBase[0];
1129
-		$cr = $this->getConnection();
1130
-		if (!$this->ldap->isResource($cr)) {
1131
-			return false;
1132
-		}
1133
-		/** @var \LDAP\Connection $cr */
1134
-		$lastFilter = null;
1135
-		if (isset($filters[count($filters) - 1])) {
1136
-			$lastFilter = $filters[count($filters) - 1];
1137
-		}
1138
-		foreach ($filters as $filter) {
1139
-			if ($lastFilter === $filter && count($foundItems) > 0) {
1140
-				//skip when the filter is a wildcard and results were found
1141
-				continue;
1142
-			}
1143
-			// 20k limit for performance and reason
1144
-			$rr = $this->ldap->search($cr, $base, $filter, [$attr], 0, 20000);
1145
-			if (!$this->ldap->isResource($rr)) {
1146
-				continue;
1147
-			}
1148
-			/** @var \LDAP\Result $rr */
1149
-			$entries = $this->ldap->countEntries($cr, $rr);
1150
-			$getEntryFunc = 'firstEntry';
1151
-			if (($entries !== false) && ($entries > 0)) {
1152
-				if (!is_null($maxF) && $entries > $maxEntries) {
1153
-					$maxEntries = $entries;
1154
-					$maxF = $filter;
1155
-				}
1156
-				$dnReadCount = 0;
1157
-				do {
1158
-					$entry = $this->ldap->$getEntryFunc($cr, $rr);
1159
-					$getEntryFunc = 'nextEntry';
1160
-					if (!$this->ldap->isResource($entry)) {
1161
-						continue 2;
1162
-					}
1163
-					$rr = $entry; //will be expected by nextEntry next round
1164
-					$attributes = $this->ldap->getAttributes($cr, $entry);
1165
-					$dn = $this->ldap->getDN($cr, $entry);
1166
-					if ($attributes === false || $dn === false || in_array($dn, $dnRead)) {
1167
-						continue;
1168
-					}
1169
-					$newItems = [];
1170
-					$state = $this->getAttributeValuesFromEntry(
1171
-						$attributes,
1172
-						$attr,
1173
-						$newItems
1174
-					);
1175
-					$dnReadCount++;
1176
-					$foundItems = array_merge($foundItems, $newItems);
1177
-					$dnRead[] = $dn;
1178
-				} while ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit);
1179
-			}
1180
-		}
1181
-
1182
-		return array_unique($foundItems);
1183
-	}
1184
-
1185
-	/**
1186
-	 * determines if and which $attr are available on the LDAP server
1187
-	 * @param string[] $objectclasses the objectclasses to use as search filter
1188
-	 * @param string $attr the attribute to look for
1189
-	 * @param string $dbkey the dbkey of the setting the feature is connected to
1190
-	 * @param string $confkey the confkey counterpart for the $dbkey as used in the
1191
-	 *                        Configuration class
1192
-	 * @param bool $po whether the objectClass with most result entries
1193
-	 *                 shall be pre-selected via the result
1194
-	 * @return array list of found items.
1195
-	 * @throws \Exception
1196
-	 */
1197
-	private function determineFeature(array $objectclasses, string $attr, string $dbkey, string $confkey, bool $po = false): array {
1198
-		$cr = $this->getConnection();
1199
-		if (!$cr) {
1200
-			throw new \Exception('Could not connect to LDAP');
1201
-		}
1202
-		$p = 'objectclass=';
1203
-		foreach ($objectclasses as $key => $value) {
1204
-			$objectclasses[$key] = $p . $value;
1205
-		}
1206
-		$maxEntryObjC = '';
1207
-
1208
-		//how deep to dig?
1209
-		//When looking for objectclasses, testing few entries is sufficient,
1210
-		$dig = 3;
1211
-
1212
-		$availableFeatures
1213
-			= $this->cumulativeSearchOnAttribute($objectclasses, $attr,
1214
-				$dig, $maxEntryObjC);
1215
-		if (is_array($availableFeatures)
1216
-		   && count($availableFeatures) > 0) {
1217
-			natcasesort($availableFeatures);
1218
-			//natcasesort keeps indices, but we must get rid of them for proper
1219
-			//sorting in the web UI. Therefore: array_values
1220
-			$this->result->addOptions($dbkey, array_values($availableFeatures));
1221
-		} else {
1222
-			throw new \Exception(self::$l->t('Could not find the desired feature'));
1223
-		}
1224
-
1225
-		$setFeatures = $this->configuration->$confkey;
1226
-		if (is_array($setFeatures) && !empty($setFeatures)) {
1227
-			//something is already configured? pre-select it.
1228
-			$this->result->addChange($dbkey, $setFeatures);
1229
-		} elseif ($po && $maxEntryObjC !== '') {
1230
-			//pre-select objectclass with most result entries
1231
-			$maxEntryObjC = str_replace($p, '', $maxEntryObjC);
1232
-			$this->applyFind($dbkey, $maxEntryObjC);
1233
-			$this->result->addChange($dbkey, $maxEntryObjC);
1234
-		}
1235
-
1236
-		return $availableFeatures;
1237
-	}
1238
-
1239
-	/**
1240
-	 * appends a list of values fr
1241
-	 * @param array $result the return value from ldap_get_attributes
1242
-	 * @param string $attribute the attribute values to look for
1243
-	 * @param array &$known new values will be appended here
1244
-	 * @return int state on of the class constants LRESULT_PROCESSED_OK,
1245
-	 *             LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
1246
-	 */
1247
-	private function getAttributeValuesFromEntry(array $result, string $attribute, array &$known): int {
1248
-		if (!isset($result['count'])
1249
-		   || !$result['count'] > 0) {
1250
-			return self::LRESULT_PROCESSED_INVALID;
1251
-		}
1252
-
1253
-		// strtolower on all keys for proper comparison
1254
-		$result = Util::mb_array_change_key_case($result);
1255
-		$attribute = strtolower($attribute);
1256
-		if (isset($result[$attribute])) {
1257
-			foreach ($result[$attribute] as $key => $val) {
1258
-				if ($key === 'count') {
1259
-					continue;
1260
-				}
1261
-				if (!in_array($val, $known)) {
1262
-					$known[] = $val;
1263
-				}
1264
-			}
1265
-			return self::LRESULT_PROCESSED_OK;
1266
-		} else {
1267
-			return self::LRESULT_PROCESSED_SKIP;
1268
-		}
1269
-	}
1270
-
1271
-	/**
1272
-	 * @return \LDAP\Connection|false a link resource on success, otherwise false
1273
-	 */
1274
-	private function getConnection(): \LDAP\Connection|false {
1275
-		if (!is_null($this->cr)) {
1276
-			return $this->cr;
1277
-		}
1278
-
1279
-		$cr = $this->ldap->connect(
1280
-			$this->configuration->ldapHost,
1281
-			$this->configuration->ldapPort
1282
-		);
1283
-
1284
-		if ($cr === false) {
1285
-			return false;
1286
-		}
1287
-
1288
-		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1289
-		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1290
-		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1291
-		if ($this->configuration->ldapTLS) {
1292
-			$this->ldap->startTls($cr);
1293
-		}
1294
-
1295
-		$lo = @$this->ldap->bind($cr,
1296
-			$this->configuration->ldapAgentName,
1297
-			$this->configuration->ldapAgentPassword);
1298
-		if ($lo === true) {
1299
-			$this->cr = $cr;
1300
-			return $cr;
1301
-		}
1302
-
1303
-		return false;
1304
-	}
1305
-
1306
-	/**
1307
-	 * @return array<array{port:int,tls:bool}>
1308
-	 */
1309
-	private function getDefaultLdapPortSettings(): array {
1310
-		static $settings = [
1311
-			['port' => 7636, 'tls' => false],
1312
-			['port' => 636, 'tls' => false],
1313
-			['port' => 7389, 'tls' => true],
1314
-			['port' => 389, 'tls' => true],
1315
-			['port' => 7389, 'tls' => false],
1316
-			['port' => 389, 'tls' => false],
1317
-		];
1318
-		return $settings;
1319
-	}
1320
-
1321
-	/**
1322
-	 * @return array<array{port:int,tls:bool}>
1323
-	 */
1324
-	private function getPortSettingsToTry(): array {
1325
-		//389 ← LDAP / Unencrypted or StartTLS
1326
-		//636 ← LDAPS / SSL
1327
-		//7xxx ← UCS. need to be checked first, because both ports may be open
1328
-		$host = $this->configuration->ldapHost;
1329
-		$port = (int)$this->configuration->ldapPort;
1330
-		$portSettings = [];
1331
-
1332
-		//In case the port is already provided, we will check this first
1333
-		if ($port > 0) {
1334
-			$hostInfo = parse_url($host);
1335
-			if (!(is_array($hostInfo)
1336
-				&& isset($hostInfo['scheme'])
1337
-				&& stripos($hostInfo['scheme'], 'ldaps') !== false)) {
1338
-				$portSettings[] = ['port' => $port, 'tls' => true];
1339
-			}
1340
-			$portSettings[] = ['port' => $port, 'tls' => false];
1341
-		} elseif ($this->configuration->usesLdapi()) {
1342
-			$portSettings[] = ['port' => 0, 'tls' => false];
1343
-		}
1344
-
1345
-		//default ports
1346
-		$portSettings = array_merge($portSettings,
1347
-			$this->getDefaultLdapPortSettings());
1348
-
1349
-		return $portSettings;
1350
-	}
19
+    protected static ?IL10N $l = null;
20
+    protected ?\LDAP\Connection $cr = null;
21
+    protected WizardResult $result;
22
+    protected LoggerInterface $logger;
23
+
24
+    public const LRESULT_PROCESSED_OK = 2;
25
+    public const LRESULT_PROCESSED_INVALID = 3;
26
+    public const LRESULT_PROCESSED_SKIP = 4;
27
+
28
+    public const LFILTER_LOGIN = 2;
29
+    public const LFILTER_USER_LIST = 3;
30
+    public const LFILTER_GROUP_LIST = 4;
31
+
32
+    public const LFILTER_MODE_ASSISTED = 2;
33
+    public const LFILTER_MODE_RAW = 1;
34
+
35
+    public const LDAP_NW_TIMEOUT = 4;
36
+
37
+    public function __construct(
38
+        protected Configuration $configuration,
39
+        ILDAPWrapper $ldap,
40
+        protected Access $access,
41
+    ) {
42
+        parent::__construct($ldap);
43
+        if (is_null(static::$l)) {
44
+            static::$l = Server::get(IL10NFactory::class)->get('user_ldap');
45
+        }
46
+        $this->result = new WizardResult();
47
+        $this->logger = Server::get(LoggerInterface::class);
48
+    }
49
+
50
+    public function __destruct() {
51
+        if ($this->result->hasChanges()) {
52
+            $this->configuration->saveConfiguration();
53
+        }
54
+    }
55
+
56
+    /**
57
+     * counts entries in the LDAP directory
58
+     *
59
+     * @param string $filter the LDAP search filter
60
+     * @param string $type a string being either 'users' or 'groups';
61
+     * @throws \Exception
62
+     */
63
+    public function countEntries(string $filter, string $type): int {
64
+        $reqs = ['ldapHost', 'ldapBase'];
65
+        if (!$this->configuration->usesLdapi()) {
66
+            $reqs[] = 'ldapPort';
67
+        }
68
+        if ($type === 'users') {
69
+            $reqs[] = 'ldapUserFilter';
70
+        }
71
+        if (!$this->checkRequirements($reqs)) {
72
+            throw new \Exception('Requirements not met', 400);
73
+        }
74
+
75
+        $attr = ['dn']; // default
76
+        $limit = 1001;
77
+        if ($type === 'groups') {
78
+            $result = $this->access->countGroups($filter, $attr, $limit);
79
+        } elseif ($type === 'users') {
80
+            $result = $this->access->countUsers($filter, $attr, $limit);
81
+        } elseif ($type === 'objects') {
82
+            $result = $this->access->countObjects($limit);
83
+        } else {
84
+            throw new \Exception('Internal error: Invalid object type', 500);
85
+        }
86
+
87
+        return (int)$result;
88
+    }
89
+
90
+    /**
91
+     * @return WizardResult|false
92
+     */
93
+    public function countGroups() {
94
+        $filter = $this->configuration->ldapGroupFilter;
95
+
96
+        if (empty($filter)) {
97
+            $output = self::$l->n('%n group found', '%n groups found', 0);
98
+            $this->result->addChange('ldap_group_count', $output);
99
+            return $this->result;
100
+        }
101
+
102
+        try {
103
+            $groupsTotal = $this->countEntries($filter, 'groups');
104
+        } catch (\Exception $e) {
105
+            //400 can be ignored, 500 is forwarded
106
+            if ($e->getCode() === 500) {
107
+                throw $e;
108
+            }
109
+            return false;
110
+        }
111
+
112
+        if ($groupsTotal > 1000) {
113
+            $output = self::$l->t('> 1000 groups found');
114
+        } else {
115
+            $output = self::$l->n(
116
+                '%n group found',
117
+                '%n groups found',
118
+                $groupsTotal
119
+            );
120
+        }
121
+        $this->result->addChange('ldap_group_count', $output);
122
+        return $this->result;
123
+    }
124
+
125
+    /**
126
+     * @throws \Exception
127
+     */
128
+    public function countUsers(): WizardResult {
129
+        $filter = $this->access->getFilterForUserCount();
130
+
131
+        $usersTotal = $this->countEntries($filter, 'users');
132
+        if ($usersTotal > 1000) {
133
+            $output = self::$l->t('> 1000 users found');
134
+        } else {
135
+            $output = self::$l->n(
136
+                '%n user found',
137
+                '%n users found',
138
+                $usersTotal
139
+            );
140
+        }
141
+        $this->result->addChange('ldap_user_count', $output);
142
+        return $this->result;
143
+    }
144
+
145
+    /**
146
+     * counts any objects in the currently set base dn
147
+     *
148
+     * @throws \Exception
149
+     */
150
+    public function countInBaseDN(): WizardResult {
151
+        // we don't need to provide a filter in this case
152
+        $total = $this->countEntries('', 'objects');
153
+        $this->result->addChange('ldap_test_base', $total);
154
+        return $this->result;
155
+    }
156
+
157
+    /**
158
+     * counts users with a specified attribute
159
+     * @return int|false
160
+     */
161
+    public function countUsersWithAttribute(string $attr, bool $existsCheck = false) {
162
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
163
+        if (!$this->configuration->usesLdapi()) {
164
+            $reqs[] = 'ldapPort';
165
+        }
166
+        if (!$this->checkRequirements($reqs)) {
167
+            return  false;
168
+        }
169
+
170
+        $filter = $this->access->combineFilterWithAnd([
171
+            $this->configuration->ldapUserFilter,
172
+            $attr . '=*'
173
+        ]);
174
+
175
+        $limit = $existsCheck ? null : 1;
176
+
177
+        return $this->access->countUsers($filter, ['dn'], $limit);
178
+    }
179
+
180
+    /**
181
+     * detects the display name attribute. If a setting is already present that
182
+     * returns at least one hit, the detection will be canceled.
183
+     * @return WizardResult|false
184
+     * @throws \Exception
185
+     */
186
+    public function detectUserDisplayNameAttribute() {
187
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
188
+        if (!$this->configuration->usesLdapi()) {
189
+            $reqs[] = 'ldapPort';
190
+        }
191
+        if (!$this->checkRequirements($reqs)) {
192
+            return  false;
193
+        }
194
+
195
+        $attr = $this->configuration->ldapUserDisplayName;
196
+        if ($attr !== '' && $attr !== 'displayName') {
197
+            // most likely not the default value with upper case N,
198
+            // verify it still produces a result
199
+            $count = (int)$this->countUsersWithAttribute($attr, true);
200
+            if ($count > 0) {
201
+                //no change, but we sent it back to make sure the user interface
202
+                //is still correct, even if the call was cancelled meanwhile
203
+                $this->result->addChange('ldap_display_name', $attr);
204
+                return $this->result;
205
+            }
206
+        }
207
+
208
+        // first attribute that has at least one result wins
209
+        $displayNameAttrs = ['displayname', 'cn'];
210
+        foreach ($displayNameAttrs as $attr) {
211
+            $count = (int)$this->countUsersWithAttribute($attr, true);
212
+
213
+            if ($count > 0) {
214
+                $this->applyFind('ldap_display_name', $attr);
215
+                return $this->result;
216
+            }
217
+        }
218
+
219
+        throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced LDAP settings.'));
220
+    }
221
+
222
+    /**
223
+     * detects the most often used email attribute for users applying to the
224
+     * user list filter. If a setting is already present that returns at least
225
+     * one hit, the detection will be canceled.
226
+     * @return WizardResult|bool
227
+     */
228
+    public function detectEmailAttribute() {
229
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
230
+        if (!$this->configuration->usesLdapi()) {
231
+            $reqs[] = 'ldapPort';
232
+        }
233
+        if (!$this->checkRequirements($reqs)) {
234
+            return  false;
235
+        }
236
+
237
+        $attr = $this->configuration->ldapEmailAttribute;
238
+        if ($attr !== '') {
239
+            $count = (int)$this->countUsersWithAttribute($attr, true);
240
+            if ($count > 0) {
241
+                return false;
242
+            }
243
+            $writeLog = true;
244
+        } else {
245
+            $writeLog = false;
246
+        }
247
+
248
+        $emailAttributes = ['mail', 'mailPrimaryAddress'];
249
+        $winner = '';
250
+        $maxUsers = 0;
251
+        foreach ($emailAttributes as $attr) {
252
+            $count = $this->countUsersWithAttribute($attr);
253
+            if ($count > $maxUsers) {
254
+                $maxUsers = $count;
255
+                $winner = $attr;
256
+            }
257
+        }
258
+
259
+        if ($winner !== '') {
260
+            $this->applyFind('ldap_email_attr', $winner);
261
+            if ($writeLog) {
262
+                $this->logger->info(
263
+                    'The mail attribute has automatically been reset, '
264
+                    . 'because the original value did not return any results.',
265
+                    ['app' => 'user_ldap']
266
+                );
267
+            }
268
+        }
269
+
270
+        return $this->result;
271
+    }
272
+
273
+    /**
274
+     * @return WizardResult|false
275
+     * @throws \Exception
276
+     */
277
+    public function determineAttributes() {
278
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
279
+        if (!$this->configuration->usesLdapi()) {
280
+            $reqs[] = 'ldapPort';
281
+        }
282
+        if (!$this->checkRequirements($reqs)) {
283
+            return  false;
284
+        }
285
+
286
+        $attributes = $this->getUserAttributes();
287
+
288
+        if (!is_array($attributes)) {
289
+            throw new \Exception('Failed to determine user attributes');
290
+        }
291
+
292
+        natcasesort($attributes);
293
+        $attributes = array_values($attributes);
294
+
295
+        $this->result->addOptions('ldap_loginfilter_attributes', $attributes);
296
+
297
+        $selected = $this->configuration->ldapLoginFilterAttributes;
298
+        if (is_array($selected) && !empty($selected)) {
299
+            $this->result->addChange('ldap_loginfilter_attributes', $selected);
300
+        }
301
+
302
+        return $this->result;
303
+    }
304
+
305
+    /**
306
+     * detects the available LDAP attributes
307
+     * @return array|false
308
+     * @throws \Exception
309
+     */
310
+    private function getUserAttributes() {
311
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
312
+        if (!$this->configuration->usesLdapi()) {
313
+            $reqs[] = 'ldapPort';
314
+        }
315
+        if (!$this->checkRequirements($reqs)) {
316
+            return  false;
317
+        }
318
+        $cr = $this->getConnection();
319
+        if (!$cr) {
320
+            throw new \Exception('Could not connect to LDAP');
321
+        }
322
+
323
+        $base = $this->configuration->ldapBase[0];
324
+        $filter = $this->configuration->ldapUserFilter;
325
+        $rr = $this->ldap->search($cr, $base, $filter, [], 1, 1);
326
+        if (!$this->ldap->isResource($rr)) {
327
+            return false;
328
+        }
329
+        /** @var \LDAP\Result $rr */
330
+        $er = $this->ldap->firstEntry($cr, $rr);
331
+        $attributes = $this->ldap->getAttributes($cr, $er);
332
+        if ($attributes === false) {
333
+            return false;
334
+        }
335
+        $pureAttributes = [];
336
+        for ($i = 0; $i < $attributes['count']; $i++) {
337
+            $pureAttributes[] = $attributes[$i];
338
+        }
339
+
340
+        return $pureAttributes;
341
+    }
342
+
343
+    /**
344
+     * detects the available LDAP groups
345
+     * @return WizardResult|false the instance's WizardResult instance
346
+     */
347
+    public function determineGroupsForGroups() {
348
+        return $this->determineGroups('ldap_groupfilter_groups',
349
+            'ldapGroupFilterGroups',
350
+            false);
351
+    }
352
+
353
+    /**
354
+     * detects the available LDAP groups
355
+     * @return WizardResult|false the instance's WizardResult instance
356
+     */
357
+    public function determineGroupsForUsers() {
358
+        return $this->determineGroups('ldap_userfilter_groups',
359
+            'ldapUserFilterGroups');
360
+    }
361
+
362
+    /**
363
+     * detects the available LDAP groups
364
+     * @return WizardResult|false the instance's WizardResult instance
365
+     * @throws \Exception
366
+     */
367
+    private function determineGroups(string $dbKey, string $confKey, bool $testMemberOf = true) {
368
+        $reqs = ['ldapHost', 'ldapBase'];
369
+        if (!$this->configuration->usesLdapi()) {
370
+            $reqs[] = 'ldapPort';
371
+        }
372
+        if (!$this->checkRequirements($reqs)) {
373
+            return  false;
374
+        }
375
+        $cr = $this->getConnection();
376
+        if (!$cr) {
377
+            throw new \Exception('Could not connect to LDAP');
378
+        }
379
+
380
+        $this->fetchGroups($dbKey, $confKey);
381
+
382
+        if ($testMemberOf) {
383
+            $this->configuration->hasMemberOfFilterSupport = (string)$this->testMemberOf();
384
+            $this->result->markChange();
385
+            if (!$this->configuration->hasMemberOfFilterSupport) {
386
+                throw new \Exception('memberOf is not supported by the server');
387
+            }
388
+        }
389
+
390
+        return $this->result;
391
+    }
392
+
393
+    /**
394
+     * fetches all groups from LDAP and adds them to the result object
395
+     *
396
+     * @throws \Exception
397
+     */
398
+    public function fetchGroups(string $dbKey, string $confKey): array {
399
+        $obclasses = ['posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames', 'groupOfUniqueNames'];
400
+
401
+        $filterParts = [];
402
+        foreach ($obclasses as $obclass) {
403
+            $filterParts[] = 'objectclass=' . $obclass;
404
+        }
405
+        //we filter for everything
406
+        //- that looks like a group and
407
+        //- has the group display name set
408
+        $filter = $this->access->combineFilterWithOr($filterParts);
409
+        $filter = $this->access->combineFilterWithAnd([$filter, 'cn=*']);
410
+
411
+        $groupNames = [];
412
+        $groupEntries = [];
413
+        $limit = 400;
414
+        $offset = 0;
415
+        do {
416
+            // we need to request dn additionally here, otherwise memberOf
417
+            // detection will fail later
418
+            $result = $this->access->searchGroups($filter, ['cn', 'dn'], $limit, $offset);
419
+            foreach ($result as $item) {
420
+                if (!isset($item['cn']) || !is_array($item['cn']) || !isset($item['cn'][0])) {
421
+                    // just in case - no issue known
422
+                    continue;
423
+                }
424
+                $groupNames[] = $item['cn'][0];
425
+                $groupEntries[] = $item;
426
+            }
427
+            $offset += $limit;
428
+        } while ($this->access->hasMoreResults());
429
+
430
+        if (count($groupNames) > 0) {
431
+            natsort($groupNames);
432
+            $this->result->addOptions($dbKey, array_values($groupNames));
433
+        } else {
434
+            throw new \Exception(self::$l->t('Could not find the desired feature'));
435
+        }
436
+
437
+        $setFeatures = $this->configuration->$confKey;
438
+        if (is_array($setFeatures) && !empty($setFeatures)) {
439
+            //something is already configured? pre-select it.
440
+            $this->result->addChange($dbKey, $setFeatures);
441
+        }
442
+        return $groupEntries;
443
+    }
444
+
445
+    /**
446
+     * @return WizardResult|false
447
+     */
448
+    public function determineGroupMemberAssoc() {
449
+        $reqs = ['ldapHost', 'ldapGroupFilter'];
450
+        if (!$this->configuration->usesLdapi()) {
451
+            $reqs[] = 'ldapPort';
452
+        }
453
+        if (!$this->checkRequirements($reqs)) {
454
+            return  false;
455
+        }
456
+        $attribute = $this->detectGroupMemberAssoc();
457
+        if ($attribute === false) {
458
+            return false;
459
+        }
460
+        $this->configuration->setConfiguration(['ldapGroupMemberAssocAttr' => $attribute]);
461
+        $this->result->addChange('ldap_group_member_assoc_attribute', $attribute);
462
+
463
+        return $this->result;
464
+    }
465
+
466
+    /**
467
+     * Detects the available object classes
468
+     * @return WizardResult|false the instance's WizardResult instance
469
+     * @throws \Exception
470
+     */
471
+    public function determineGroupObjectClasses() {
472
+        $reqs = ['ldapHost', 'ldapBase'];
473
+        if (!$this->configuration->usesLdapi()) {
474
+            $reqs[] = 'ldapPort';
475
+        }
476
+        if (!$this->checkRequirements($reqs)) {
477
+            return  false;
478
+        }
479
+        $cr = $this->getConnection();
480
+        if (!$cr) {
481
+            throw new \Exception('Could not connect to LDAP');
482
+        }
483
+
484
+        $obclasses = ['groupOfNames', 'groupOfUniqueNames', 'group', 'posixGroup', '*'];
485
+        $this->determineFeature($obclasses,
486
+            'objectclass',
487
+            'ldap_groupfilter_objectclass',
488
+            'ldapGroupFilterObjectclass',
489
+            false);
490
+
491
+        return $this->result;
492
+    }
493
+
494
+    /**
495
+     * detects the available object classes
496
+     * @return WizardResult|false
497
+     * @throws \Exception
498
+     */
499
+    public function determineUserObjectClasses() {
500
+        $reqs = ['ldapHost', 'ldapBase'];
501
+        if (!$this->configuration->usesLdapi()) {
502
+            $reqs[] = 'ldapPort';
503
+        }
504
+        if (!$this->checkRequirements($reqs)) {
505
+            return  false;
506
+        }
507
+        $cr = $this->getConnection();
508
+        if (!$cr) {
509
+            throw new \Exception('Could not connect to LDAP');
510
+        }
511
+
512
+        $obclasses = ['inetOrgPerson', 'person', 'organizationalPerson',
513
+            'user', 'posixAccount', '*'];
514
+        $filter = $this->configuration->ldapUserFilter;
515
+        //if filter is empty, it is probably the first time the wizard is called
516
+        //then, apply suggestions.
517
+        $this->determineFeature($obclasses,
518
+            'objectclass',
519
+            'ldap_userfilter_objectclass',
520
+            'ldapUserFilterObjectclass',
521
+            empty($filter));
522
+
523
+        return $this->result;
524
+    }
525
+
526
+    /**
527
+     * @return WizardResult|false
528
+     * @throws \Exception
529
+     */
530
+    public function getGroupFilter() {
531
+        $reqs = ['ldapHost', 'ldapBase'];
532
+        if (!$this->configuration->usesLdapi()) {
533
+            $reqs[] = 'ldapPort';
534
+        }
535
+        if (!$this->checkRequirements($reqs)) {
536
+            return false;
537
+        }
538
+        //make sure the use display name is set
539
+        $displayName = $this->configuration->ldapGroupDisplayName;
540
+        if ($displayName === '') {
541
+            $d = $this->configuration->getDefaults();
542
+            $this->applyFind('ldap_group_display_name',
543
+                $d['ldap_group_display_name']);
544
+        }
545
+        $filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST);
546
+
547
+        $this->applyFind('ldap_group_filter', $filter);
548
+        return $this->result;
549
+    }
550
+
551
+    /**
552
+     * @return WizardResult|false
553
+     * @throws \Exception
554
+     */
555
+    public function getUserListFilter() {
556
+        $reqs = ['ldapHost', 'ldapBase'];
557
+        if (!$this->configuration->usesLdapi()) {
558
+            $reqs[] = 'ldapPort';
559
+        }
560
+        if (!$this->checkRequirements($reqs)) {
561
+            return false;
562
+        }
563
+        //make sure the use display name is set
564
+        $displayName = $this->configuration->ldapUserDisplayName;
565
+        if ($displayName === '') {
566
+            $d = $this->configuration->getDefaults();
567
+            $this->applyFind('ldap_display_name', $d['ldap_display_name']);
568
+        }
569
+        $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST);
570
+        if (!$filter) {
571
+            throw new \Exception('Cannot create filter');
572
+        }
573
+
574
+        $this->applyFind('ldap_userlist_filter', $filter);
575
+        return $this->result;
576
+    }
577
+
578
+    /**
579
+     * @return WizardResult|false
580
+     * @throws \Exception
581
+     */
582
+    public function getUserLoginFilter() {
583
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
584
+        if (!$this->configuration->usesLdapi()) {
585
+            $reqs[] = 'ldapPort';
586
+        }
587
+        if (!$this->checkRequirements($reqs)) {
588
+            return false;
589
+        }
590
+
591
+        $filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
592
+        if (!$filter) {
593
+            throw new \Exception('Cannot create filter');
594
+        }
595
+
596
+        $this->applyFind('ldap_login_filter', $filter);
597
+        return $this->result;
598
+    }
599
+
600
+    /**
601
+     * @return WizardResult|false
602
+     * @throws \Exception
603
+     */
604
+    public function testLoginName(string $loginName) {
605
+        $reqs = ['ldapHost', 'ldapBase', 'ldapUserFilter'];
606
+        if (!$this->configuration->usesLdapi()) {
607
+            $reqs[] = 'ldapPort';
608
+        }
609
+        if (!$this->checkRequirements($reqs)) {
610
+            return false;
611
+        }
612
+
613
+        $cr = $this->access->connection->getConnectionResource();
614
+
615
+        if (mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
616
+            === false) {
617
+            throw new \Exception('missing placeholder');
618
+        }
619
+
620
+        $users = $this->access->countUsersByLoginName($loginName);
621
+        if ($this->ldap->errno($cr) !== 0) {
622
+            throw new \Exception($this->ldap->error($cr));
623
+        }
624
+        $filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
625
+        $this->result->addChange('ldap_test_loginname', $users);
626
+        $this->result->addChange('ldap_test_effective_filter', $filter);
627
+        return $this->result;
628
+    }
629
+
630
+    /**
631
+     * Tries to determine the port, requires given Host, User DN and Password
632
+     * @return WizardResult|false WizardResult on success, false otherwise
633
+     * @throws \Exception
634
+     */
635
+    public function guessPortAndTLS() {
636
+        if (!$this->checkRequirements(['ldapHost',
637
+        ])) {
638
+            return false;
639
+        }
640
+        $this->checkHost();
641
+        $portSettings = $this->getPortSettingsToTry();
642
+
643
+        //proceed from the best configuration and return on first success
644
+        foreach ($portSettings as $setting) {
645
+            $p = $setting['port'];
646
+            $t = $setting['tls'];
647
+            $this->logger->debug(
648
+                'Wiz: trying port ' . $p . ', TLS ' . $t,
649
+                ['app' => 'user_ldap']
650
+            );
651
+            //connectAndBind may throw Exception, it needs to be caught by the
652
+            //callee of this method
653
+
654
+            try {
655
+                $settingsFound = $this->connectAndBind($p, $t);
656
+            } catch (\Exception $e) {
657
+                // any reply other than -1 (= cannot connect) is already okay,
658
+                // because then we found the server
659
+                // unavailable startTLS returns -11
660
+                if ($e->getCode() > 0) {
661
+                    $settingsFound = true;
662
+                } else {
663
+                    throw $e;
664
+                }
665
+            }
666
+
667
+            if ($settingsFound === true) {
668
+                $config = [
669
+                    'ldapPort' => (string)$p,
670
+                    'ldapTLS' => (string)$t,
671
+                ];
672
+                $this->configuration->setConfiguration($config);
673
+                $this->logger->debug(
674
+                    'Wiz: detected Port ' . $p,
675
+                    ['app' => 'user_ldap']
676
+                );
677
+                $this->result->addChange('ldap_port', $p);
678
+                return $this->result;
679
+            }
680
+        }
681
+
682
+        //custom port, undetected (we do not brute force)
683
+        return false;
684
+    }
685
+
686
+    /**
687
+     * tries to determine a base dn from User DN or LDAP Host
688
+     * @return WizardResult|false WizardResult on success, false otherwise
689
+     */
690
+    public function guessBaseDN() {
691
+        $reqs = ['ldapHost'];
692
+        if (!$this->configuration->usesLdapi()) {
693
+            $reqs[] = 'ldapPort';
694
+        }
695
+        if (!$this->checkRequirements($reqs)) {
696
+            return false;
697
+        }
698
+
699
+        //check whether a DN is given in the agent name (99.9% of all cases)
700
+        $base = null;
701
+        $i = stripos($this->configuration->ldapAgentName, 'dc=');
702
+        if ($i !== false) {
703
+            $base = substr($this->configuration->ldapAgentName, $i);
704
+            if ($this->testBaseDN($base)) {
705
+                $this->applyFind('ldap_base', $base);
706
+                return $this->result;
707
+            }
708
+        }
709
+
710
+        //this did not help :(
711
+        //Let's see whether we can parse the Host URL and convert the domain to
712
+        //a base DN
713
+        $helper = Server::get(Helper::class);
714
+        $domain = $helper->getDomainFromURL($this->configuration->ldapHost);
715
+        if (!$domain) {
716
+            return false;
717
+        }
718
+
719
+        $dparts = explode('.', $domain);
720
+        while (count($dparts) > 0) {
721
+            $base2 = 'dc=' . implode(',dc=', $dparts);
722
+            if ($base !== $base2 && $this->testBaseDN($base2)) {
723
+                $this->applyFind('ldap_base', $base2);
724
+                return $this->result;
725
+            }
726
+            array_shift($dparts);
727
+        }
728
+
729
+        return false;
730
+    }
731
+
732
+    /**
733
+     * sets the found value for the configuration key in the WizardResult
734
+     * as well as in the Configuration instance
735
+     * @param string $key the configuration key
736
+     * @param string $value the (detected) value
737
+     *
738
+     */
739
+    private function applyFind(string $key, string $value): void {
740
+        $this->result->addChange($key, $value);
741
+        $this->configuration->setConfiguration([$key => $value]);
742
+    }
743
+
744
+    /**
745
+     * Checks, whether a port was entered in the Host configuration
746
+     * field. In this case the port will be stripped off, but also stored as
747
+     * setting.
748
+     */
749
+    private function checkHost(): void {
750
+        $host = $this->configuration->ldapHost;
751
+        $hostInfo = parse_url($host);
752
+
753
+        //removes Port from Host
754
+        if (is_array($hostInfo) && isset($hostInfo['port'])) {
755
+            $port = $hostInfo['port'];
756
+            $host = str_replace(':' . $port, '', $host);
757
+            $this->applyFind('ldap_host', $host);
758
+            $this->applyFind('ldap_port', (string)$port);
759
+        }
760
+    }
761
+
762
+    /**
763
+     * tries to detect the group member association attribute which is
764
+     * one of 'uniqueMember', 'memberUid', 'member', 'gidNumber'
765
+     * @return string|false string with the attribute name, false on error
766
+     * @throws \Exception
767
+     */
768
+    private function detectGroupMemberAssoc() {
769
+        $possibleAttrs = ['uniqueMember', 'memberUid', 'member', 'gidNumber', 'zimbraMailForwardingAddress'];
770
+        $filter = $this->configuration->ldapGroupFilter;
771
+        if (empty($filter)) {
772
+            return false;
773
+        }
774
+        $cr = $this->getConnection();
775
+        if (!$cr) {
776
+            throw new \Exception('Could not connect to LDAP');
777
+        }
778
+        $base = $this->configuration->ldapBaseGroups[0] ?: $this->configuration->ldapBase[0];
779
+        $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000);
780
+        if (!$this->ldap->isResource($rr)) {
781
+            return false;
782
+        }
783
+        /** @var \LDAP\Result $rr */
784
+        $er = $this->ldap->firstEntry($cr, $rr);
785
+        while ($this->ldap->isResource($er)) {
786
+            $this->ldap->getDN($cr, $er);
787
+            $attrs = $this->ldap->getAttributes($cr, $er);
788
+            $result = [];
789
+            $possibleAttrsCount = count($possibleAttrs);
790
+            for ($i = 0; $i < $possibleAttrsCount; $i++) {
791
+                if (isset($attrs[$possibleAttrs[$i]])) {
792
+                    $result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count'];
793
+                }
794
+            }
795
+            if (!empty($result)) {
796
+                natsort($result);
797
+                return key($result);
798
+            }
799
+
800
+            $er = $this->ldap->nextEntry($cr, $er);
801
+        }
802
+
803
+        return false;
804
+    }
805
+
806
+    /**
807
+     * Checks whether for a given BaseDN results will be returned
808
+     * @param string $base the BaseDN to test
809
+     * @return bool true on success, false otherwise
810
+     * @throws \Exception
811
+     */
812
+    private function testBaseDN(string $base): bool {
813
+        $cr = $this->getConnection();
814
+        if (!$cr) {
815
+            throw new \Exception('Could not connect to LDAP');
816
+        }
817
+
818
+        //base is there, let's validate it. If we search for anything, we should
819
+        //get a result set > 0 on a proper base
820
+        $rr = $this->ldap->search($cr, $base, 'objectClass=*', ['dn'], 0, 1);
821
+        if (!$this->ldap->isResource($rr)) {
822
+            $errorNo = $this->ldap->errno($cr);
823
+            $errorMsg = $this->ldap->error($cr);
824
+            $this->logger->info(
825
+                'Wiz: Could not search base ' . $base . ' Error ' . $errorNo . ': ' . $errorMsg,
826
+                ['app' => 'user_ldap']
827
+            );
828
+            return false;
829
+        }
830
+        /** @var \LDAP\Result $rr */
831
+        $entries = $this->ldap->countEntries($cr, $rr);
832
+        return ($entries !== false) && ($entries > 0);
833
+    }
834
+
835
+    /**
836
+     * Checks whether the server supports memberOf in LDAP Filter.
837
+     * Note: at least in OpenLDAP, availability of memberOf is dependent on
838
+     * a configured objectClass. I.e. not necessarily for all available groups
839
+     * memberOf does work.
840
+     *
841
+     * @return bool true if it does, false otherwise
842
+     * @throws \Exception
843
+     */
844
+    private function testMemberOf(): bool {
845
+        $cr = $this->getConnection();
846
+        if (!$cr) {
847
+            throw new \Exception('Could not connect to LDAP');
848
+        }
849
+        $result = $this->access->countUsers('memberOf=*', ['memberOf'], 1);
850
+        if (is_int($result) && $result > 0) {
851
+            return true;
852
+        }
853
+        return false;
854
+    }
855
+
856
+    /**
857
+     * creates an LDAP Filter from given configuration
858
+     * @param int $filterType int, for which use case the filter shall be created
859
+     *                        can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or
860
+     *                        self::LFILTER_GROUP_LIST
861
+     * @throws \Exception
862
+     */
863
+    private function composeLdapFilter(int $filterType): string {
864
+        $filter = '';
865
+        $parts = 0;
866
+        switch ($filterType) {
867
+            case self::LFILTER_USER_LIST:
868
+                $objcs = $this->configuration->ldapUserFilterObjectclass;
869
+                //glue objectclasses
870
+                if (is_array($objcs) && count($objcs) > 0) {
871
+                    $filter .= '(|';
872
+                    foreach ($objcs as $objc) {
873
+                        $filter .= '(objectclass=' . ldap_escape($objc, '', LDAP_ESCAPE_FILTER) . ')';
874
+                    }
875
+                    $filter .= ')';
876
+                    $parts++;
877
+                }
878
+                //glue group memberships
879
+                if ($this->configuration->hasMemberOfFilterSupport) {
880
+                    $cns = $this->configuration->ldapUserFilterGroups;
881
+                    if (is_array($cns) && count($cns) > 0) {
882
+                        $filter .= '(|';
883
+                        $cr = $this->getConnection();
884
+                        if (!$cr) {
885
+                            throw new \Exception('Could not connect to LDAP');
886
+                        }
887
+                        $base = $this->configuration->ldapBase[0];
888
+                        foreach ($cns as $cn) {
889
+                            $rr = $this->ldap->search($cr, $base, 'cn=' . ldap_escape($cn, '', LDAP_ESCAPE_FILTER), ['dn', 'primaryGroupToken']);
890
+                            if (!$this->ldap->isResource($rr)) {
891
+                                continue;
892
+                            }
893
+                            /** @var \LDAP\Result $rr */
894
+                            $er = $this->ldap->firstEntry($cr, $rr);
895
+                            $attrs = $this->ldap->getAttributes($cr, $er);
896
+                            $dn = $this->ldap->getDN($cr, $er);
897
+                            if ($dn === false || $dn === '') {
898
+                                continue;
899
+                            }
900
+                            $filterPart = '(memberof=' . ldap_escape($dn, '', LDAP_ESCAPE_FILTER) . ')';
901
+                            if (isset($attrs['primaryGroupToken'])) {
902
+                                $pgt = $attrs['primaryGroupToken'][0];
903
+                                $primaryFilterPart = '(primaryGroupID=' . ldap_escape($pgt, '', LDAP_ESCAPE_FILTER) . ')';
904
+                                $filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
905
+                            }
906
+                            $filter .= $filterPart;
907
+                        }
908
+                        $filter .= ')';
909
+                    }
910
+                    $parts++;
911
+                }
912
+                //wrap parts in AND condition
913
+                if ($parts > 1) {
914
+                    $filter = '(&' . $filter . ')';
915
+                }
916
+                if ($filter === '') {
917
+                    $filter = '(objectclass=*)';
918
+                }
919
+                break;
920
+
921
+            case self::LFILTER_GROUP_LIST:
922
+                $objcs = $this->configuration->ldapGroupFilterObjectclass;
923
+                //glue objectclasses
924
+                if (is_array($objcs) && count($objcs) > 0) {
925
+                    $filter .= '(|';
926
+                    foreach ($objcs as $objc) {
927
+                        $filter .= '(objectclass=' . ldap_escape($objc, '', LDAP_ESCAPE_FILTER) . ')';
928
+                    }
929
+                    $filter .= ')';
930
+                    $parts++;
931
+                }
932
+                //glue group memberships
933
+                $cns = $this->configuration->ldapGroupFilterGroups;
934
+                if (is_array($cns) && count($cns) > 0) {
935
+                    $filter .= '(|';
936
+                    foreach ($cns as $cn) {
937
+                        $filter .= '(cn=' . ldap_escape($cn, '', LDAP_ESCAPE_FILTER) . ')';
938
+                    }
939
+                    $filter .= ')';
940
+                }
941
+                $parts++;
942
+                //wrap parts in AND condition
943
+                if ($parts > 1) {
944
+                    $filter = '(&' . $filter . ')';
945
+                }
946
+                break;
947
+
948
+            case self::LFILTER_LOGIN:
949
+                $ulf = $this->configuration->ldapUserFilter;
950
+                $loginpart = '=%uid';
951
+                $filterUsername = '';
952
+                $userAttributes = $this->getUserAttributes();
953
+                if ($userAttributes === false) {
954
+                    throw new \Exception('Failed to get user attributes');
955
+                }
956
+                $userAttributes = array_change_key_case(array_flip($userAttributes));
957
+                $parts = 0;
958
+
959
+                if ($this->configuration->ldapLoginFilterUsername === '1') {
960
+                    $attr = '';
961
+                    if (isset($userAttributes['uid'])) {
962
+                        $attr = 'uid';
963
+                    } elseif (isset($userAttributes['samaccountname'])) {
964
+                        $attr = 'samaccountname';
965
+                    } elseif (isset($userAttributes['cn'])) {
966
+                        //fallback
967
+                        $attr = 'cn';
968
+                    }
969
+                    if ($attr !== '') {
970
+                        $filterUsername = '(' . $attr . $loginpart . ')';
971
+                        $parts++;
972
+                    }
973
+                }
974
+
975
+                $filterEmail = '';
976
+                if ($this->configuration->ldapLoginFilterEmail === '1') {
977
+                    $filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))';
978
+                    $parts++;
979
+                }
980
+
981
+                $filterAttributes = '';
982
+                $attrsToFilter = $this->configuration->ldapLoginFilterAttributes;
983
+                if (is_array($attrsToFilter) && count($attrsToFilter) > 0) {
984
+                    $filterAttributes = '(|';
985
+                    foreach ($attrsToFilter as $attribute) {
986
+                        $filterAttributes .= '(' . $attribute . $loginpart . ')';
987
+                    }
988
+                    $filterAttributes .= ')';
989
+                    $parts++;
990
+                }
991
+
992
+                $filterLogin = '';
993
+                if ($parts > 1) {
994
+                    $filterLogin = '(|';
995
+                }
996
+                $filterLogin .= $filterUsername;
997
+                $filterLogin .= $filterEmail;
998
+                $filterLogin .= $filterAttributes;
999
+                if ($parts > 1) {
1000
+                    $filterLogin .= ')';
1001
+                }
1002
+
1003
+                $filter = '(&' . $ulf . $filterLogin . ')';
1004
+                break;
1005
+        }
1006
+
1007
+        $this->logger->debug(
1008
+            'Wiz: Final filter ' . $filter,
1009
+            ['app' => 'user_ldap']
1010
+        );
1011
+
1012
+        return $filter;
1013
+    }
1014
+
1015
+    /**
1016
+     * Connects and Binds to an LDAP Server
1017
+     *
1018
+     * @param int $port the port to connect with
1019
+     * @param bool $tls whether startTLS is to be used
1020
+     * @throws \Exception
1021
+     */
1022
+    private function connectAndBind(int $port, bool $tls): bool {
1023
+        //connect, does not really trigger any server communication
1024
+        $host = $this->configuration->ldapHost;
1025
+        $hostInfo = parse_url((string)$host);
1026
+        if (!is_string($host) || !$hostInfo) {
1027
+            throw new \Exception(self::$l->t('Invalid Host'));
1028
+        }
1029
+        $this->logger->debug(
1030
+            'Wiz: Attempting to connect',
1031
+            ['app' => 'user_ldap']
1032
+        );
1033
+        $cr = $this->ldap->connect($host, (string)$port);
1034
+        if (!$this->ldap->isResource($cr)) {
1035
+            throw new \Exception(self::$l->t('Invalid Host'));
1036
+        }
1037
+        /** @var \LDAP\Connection $cr */
1038
+
1039
+        //set LDAP options
1040
+        $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1041
+        $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1042
+        $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1043
+
1044
+        try {
1045
+            if ($tls) {
1046
+                $isTlsWorking = @$this->ldap->startTls($cr);
1047
+                if (!$isTlsWorking) {
1048
+                    return false;
1049
+                }
1050
+            }
1051
+
1052
+            $this->logger->debug(
1053
+                'Wiz: Attempting to Bind',
1054
+                ['app' => 'user_ldap']
1055
+            );
1056
+            //interesting part: do the bind!
1057
+            $login = $this->ldap->bind($cr,
1058
+                $this->configuration->ldapAgentName,
1059
+                $this->configuration->ldapAgentPassword
1060
+            );
1061
+            $errNo = $this->ldap->errno($cr);
1062
+            $error = $this->ldap->error($cr);
1063
+            $this->ldap->unbind($cr);
1064
+        } catch (ServerNotAvailableException $e) {
1065
+            return false;
1066
+        }
1067
+
1068
+        if ($login === true) {
1069
+            $this->logger->debug(
1070
+                'Wiz: Bind successful to Port ' . $port . ' TLS ' . (int)$tls,
1071
+                ['app' => 'user_ldap']
1072
+            );
1073
+            return true;
1074
+        }
1075
+
1076
+        if ($errNo === -1) {
1077
+            //host, port or TLS wrong
1078
+            return false;
1079
+        }
1080
+        throw new \Exception($error, $errNo);
1081
+    }
1082
+
1083
+    /**
1084
+     * checks whether a valid combination of agent and password has been
1085
+     * provided (either two values or nothing for anonymous connect)
1086
+     * @return bool true if everything is fine, false otherwise
1087
+     */
1088
+    private function checkAgentRequirements(): bool {
1089
+        $agent = $this->configuration->ldapAgentName;
1090
+        $pwd = $this->configuration->ldapAgentPassword;
1091
+
1092
+        return
1093
+            ($agent !== '' && $pwd !== '')
1094
+            || ($agent === '' && $pwd === '')
1095
+        ;
1096
+    }
1097
+
1098
+    private function checkRequirements(array $reqs): bool {
1099
+        $this->checkAgentRequirements();
1100
+        foreach ($reqs as $option) {
1101
+            $value = $this->configuration->$option;
1102
+            if (empty($value)) {
1103
+                return false;
1104
+            }
1105
+        }
1106
+        return true;
1107
+    }
1108
+
1109
+    /**
1110
+     * does a cumulativeSearch on LDAP to get different values of a
1111
+     * specified attribute
1112
+     * @param string[] $filters array, the filters that shall be used in the search
1113
+     * @param string $attr the attribute of which a list of values shall be returned
1114
+     * @param int $dnReadLimit the amount of how many DNs should be analyzed.
1115
+     *                         The lower, the faster
1116
+     * @param string $maxF string. if not null, this variable will have the filter that
1117
+     *                     yields most result entries
1118
+     * @return array|false an array with the values on success, false otherwise
1119
+     */
1120
+    public function cumulativeSearchOnAttribute(array $filters, string $attr, int $dnReadLimit = 3, ?string &$maxF = null) {
1121
+        $dnRead = [];
1122
+        $foundItems = [];
1123
+        $maxEntries = 0;
1124
+        if (!is_array($this->configuration->ldapBase)
1125
+           || !isset($this->configuration->ldapBase[0])) {
1126
+            return false;
1127
+        }
1128
+        $base = $this->configuration->ldapBase[0];
1129
+        $cr = $this->getConnection();
1130
+        if (!$this->ldap->isResource($cr)) {
1131
+            return false;
1132
+        }
1133
+        /** @var \LDAP\Connection $cr */
1134
+        $lastFilter = null;
1135
+        if (isset($filters[count($filters) - 1])) {
1136
+            $lastFilter = $filters[count($filters) - 1];
1137
+        }
1138
+        foreach ($filters as $filter) {
1139
+            if ($lastFilter === $filter && count($foundItems) > 0) {
1140
+                //skip when the filter is a wildcard and results were found
1141
+                continue;
1142
+            }
1143
+            // 20k limit for performance and reason
1144
+            $rr = $this->ldap->search($cr, $base, $filter, [$attr], 0, 20000);
1145
+            if (!$this->ldap->isResource($rr)) {
1146
+                continue;
1147
+            }
1148
+            /** @var \LDAP\Result $rr */
1149
+            $entries = $this->ldap->countEntries($cr, $rr);
1150
+            $getEntryFunc = 'firstEntry';
1151
+            if (($entries !== false) && ($entries > 0)) {
1152
+                if (!is_null($maxF) && $entries > $maxEntries) {
1153
+                    $maxEntries = $entries;
1154
+                    $maxF = $filter;
1155
+                }
1156
+                $dnReadCount = 0;
1157
+                do {
1158
+                    $entry = $this->ldap->$getEntryFunc($cr, $rr);
1159
+                    $getEntryFunc = 'nextEntry';
1160
+                    if (!$this->ldap->isResource($entry)) {
1161
+                        continue 2;
1162
+                    }
1163
+                    $rr = $entry; //will be expected by nextEntry next round
1164
+                    $attributes = $this->ldap->getAttributes($cr, $entry);
1165
+                    $dn = $this->ldap->getDN($cr, $entry);
1166
+                    if ($attributes === false || $dn === false || in_array($dn, $dnRead)) {
1167
+                        continue;
1168
+                    }
1169
+                    $newItems = [];
1170
+                    $state = $this->getAttributeValuesFromEntry(
1171
+                        $attributes,
1172
+                        $attr,
1173
+                        $newItems
1174
+                    );
1175
+                    $dnReadCount++;
1176
+                    $foundItems = array_merge($foundItems, $newItems);
1177
+                    $dnRead[] = $dn;
1178
+                } while ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit);
1179
+            }
1180
+        }
1181
+
1182
+        return array_unique($foundItems);
1183
+    }
1184
+
1185
+    /**
1186
+     * determines if and which $attr are available on the LDAP server
1187
+     * @param string[] $objectclasses the objectclasses to use as search filter
1188
+     * @param string $attr the attribute to look for
1189
+     * @param string $dbkey the dbkey of the setting the feature is connected to
1190
+     * @param string $confkey the confkey counterpart for the $dbkey as used in the
1191
+     *                        Configuration class
1192
+     * @param bool $po whether the objectClass with most result entries
1193
+     *                 shall be pre-selected via the result
1194
+     * @return array list of found items.
1195
+     * @throws \Exception
1196
+     */
1197
+    private function determineFeature(array $objectclasses, string $attr, string $dbkey, string $confkey, bool $po = false): array {
1198
+        $cr = $this->getConnection();
1199
+        if (!$cr) {
1200
+            throw new \Exception('Could not connect to LDAP');
1201
+        }
1202
+        $p = 'objectclass=';
1203
+        foreach ($objectclasses as $key => $value) {
1204
+            $objectclasses[$key] = $p . $value;
1205
+        }
1206
+        $maxEntryObjC = '';
1207
+
1208
+        //how deep to dig?
1209
+        //When looking for objectclasses, testing few entries is sufficient,
1210
+        $dig = 3;
1211
+
1212
+        $availableFeatures
1213
+            = $this->cumulativeSearchOnAttribute($objectclasses, $attr,
1214
+                $dig, $maxEntryObjC);
1215
+        if (is_array($availableFeatures)
1216
+           && count($availableFeatures) > 0) {
1217
+            natcasesort($availableFeatures);
1218
+            //natcasesort keeps indices, but we must get rid of them for proper
1219
+            //sorting in the web UI. Therefore: array_values
1220
+            $this->result->addOptions($dbkey, array_values($availableFeatures));
1221
+        } else {
1222
+            throw new \Exception(self::$l->t('Could not find the desired feature'));
1223
+        }
1224
+
1225
+        $setFeatures = $this->configuration->$confkey;
1226
+        if (is_array($setFeatures) && !empty($setFeatures)) {
1227
+            //something is already configured? pre-select it.
1228
+            $this->result->addChange($dbkey, $setFeatures);
1229
+        } elseif ($po && $maxEntryObjC !== '') {
1230
+            //pre-select objectclass with most result entries
1231
+            $maxEntryObjC = str_replace($p, '', $maxEntryObjC);
1232
+            $this->applyFind($dbkey, $maxEntryObjC);
1233
+            $this->result->addChange($dbkey, $maxEntryObjC);
1234
+        }
1235
+
1236
+        return $availableFeatures;
1237
+    }
1238
+
1239
+    /**
1240
+     * appends a list of values fr
1241
+     * @param array $result the return value from ldap_get_attributes
1242
+     * @param string $attribute the attribute values to look for
1243
+     * @param array &$known new values will be appended here
1244
+     * @return int state on of the class constants LRESULT_PROCESSED_OK,
1245
+     *             LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
1246
+     */
1247
+    private function getAttributeValuesFromEntry(array $result, string $attribute, array &$known): int {
1248
+        if (!isset($result['count'])
1249
+           || !$result['count'] > 0) {
1250
+            return self::LRESULT_PROCESSED_INVALID;
1251
+        }
1252
+
1253
+        // strtolower on all keys for proper comparison
1254
+        $result = Util::mb_array_change_key_case($result);
1255
+        $attribute = strtolower($attribute);
1256
+        if (isset($result[$attribute])) {
1257
+            foreach ($result[$attribute] as $key => $val) {
1258
+                if ($key === 'count') {
1259
+                    continue;
1260
+                }
1261
+                if (!in_array($val, $known)) {
1262
+                    $known[] = $val;
1263
+                }
1264
+            }
1265
+            return self::LRESULT_PROCESSED_OK;
1266
+        } else {
1267
+            return self::LRESULT_PROCESSED_SKIP;
1268
+        }
1269
+    }
1270
+
1271
+    /**
1272
+     * @return \LDAP\Connection|false a link resource on success, otherwise false
1273
+     */
1274
+    private function getConnection(): \LDAP\Connection|false {
1275
+        if (!is_null($this->cr)) {
1276
+            return $this->cr;
1277
+        }
1278
+
1279
+        $cr = $this->ldap->connect(
1280
+            $this->configuration->ldapHost,
1281
+            $this->configuration->ldapPort
1282
+        );
1283
+
1284
+        if ($cr === false) {
1285
+            return false;
1286
+        }
1287
+
1288
+        $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1289
+        $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1290
+        $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1291
+        if ($this->configuration->ldapTLS) {
1292
+            $this->ldap->startTls($cr);
1293
+        }
1294
+
1295
+        $lo = @$this->ldap->bind($cr,
1296
+            $this->configuration->ldapAgentName,
1297
+            $this->configuration->ldapAgentPassword);
1298
+        if ($lo === true) {
1299
+            $this->cr = $cr;
1300
+            return $cr;
1301
+        }
1302
+
1303
+        return false;
1304
+    }
1305
+
1306
+    /**
1307
+     * @return array<array{port:int,tls:bool}>
1308
+     */
1309
+    private function getDefaultLdapPortSettings(): array {
1310
+        static $settings = [
1311
+            ['port' => 7636, 'tls' => false],
1312
+            ['port' => 636, 'tls' => false],
1313
+            ['port' => 7389, 'tls' => true],
1314
+            ['port' => 389, 'tls' => true],
1315
+            ['port' => 7389, 'tls' => false],
1316
+            ['port' => 389, 'tls' => false],
1317
+        ];
1318
+        return $settings;
1319
+    }
1320
+
1321
+    /**
1322
+     * @return array<array{port:int,tls:bool}>
1323
+     */
1324
+    private function getPortSettingsToTry(): array {
1325
+        //389 ← LDAP / Unencrypted or StartTLS
1326
+        //636 ← LDAPS / SSL
1327
+        //7xxx ← UCS. need to be checked first, because both ports may be open
1328
+        $host = $this->configuration->ldapHost;
1329
+        $port = (int)$this->configuration->ldapPort;
1330
+        $portSettings = [];
1331
+
1332
+        //In case the port is already provided, we will check this first
1333
+        if ($port > 0) {
1334
+            $hostInfo = parse_url($host);
1335
+            if (!(is_array($hostInfo)
1336
+                && isset($hostInfo['scheme'])
1337
+                && stripos($hostInfo['scheme'], 'ldaps') !== false)) {
1338
+                $portSettings[] = ['port' => $port, 'tls' => true];
1339
+            }
1340
+            $portSettings[] = ['port' => $port, 'tls' => false];
1341
+        } elseif ($this->configuration->usesLdapi()) {
1342
+            $portSettings[] = ['port' => 0, 'tls' => false];
1343
+        }
1344
+
1345
+        //default ports
1346
+        $portSettings = array_merge($portSettings,
1347
+            $this->getDefaultLdapPortSettings());
1348
+
1349
+        return $portSettings;
1350
+    }
1351 1351
 }
Please login to merge, or discard this patch.
Spacing   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 			throw new \Exception('Internal error: Invalid object type', 500);
85 85
 		}
86 86
 
87
-		return (int)$result;
87
+		return (int) $result;
88 88
 	}
89 89
 
90 90
 	/**
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 
170 170
 		$filter = $this->access->combineFilterWithAnd([
171 171
 			$this->configuration->ldapUserFilter,
172
-			$attr . '=*'
172
+			$attr.'=*'
173 173
 		]);
174 174
 
175 175
 		$limit = $existsCheck ? null : 1;
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
 		if ($attr !== '' && $attr !== 'displayName') {
197 197
 			// most likely not the default value with upper case N,
198 198
 			// verify it still produces a result
199
-			$count = (int)$this->countUsersWithAttribute($attr, true);
199
+			$count = (int) $this->countUsersWithAttribute($attr, true);
200 200
 			if ($count > 0) {
201 201
 				//no change, but we sent it back to make sure the user interface
202 202
 				//is still correct, even if the call was cancelled meanwhile
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 		// first attribute that has at least one result wins
209 209
 		$displayNameAttrs = ['displayname', 'cn'];
210 210
 		foreach ($displayNameAttrs as $attr) {
211
-			$count = (int)$this->countUsersWithAttribute($attr, true);
211
+			$count = (int) $this->countUsersWithAttribute($attr, true);
212 212
 
213 213
 			if ($count > 0) {
214 214
 				$this->applyFind('ldap_display_name', $attr);
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
 
237 237
 		$attr = $this->configuration->ldapEmailAttribute;
238 238
 		if ($attr !== '') {
239
-			$count = (int)$this->countUsersWithAttribute($attr, true);
239
+			$count = (int) $this->countUsersWithAttribute($attr, true);
240 240
 			if ($count > 0) {
241 241
 				return false;
242 242
 			}
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
 		$this->fetchGroups($dbKey, $confKey);
381 381
 
382 382
 		if ($testMemberOf) {
383
-			$this->configuration->hasMemberOfFilterSupport = (string)$this->testMemberOf();
383
+			$this->configuration->hasMemberOfFilterSupport = (string) $this->testMemberOf();
384 384
 			$this->result->markChange();
385 385
 			if (!$this->configuration->hasMemberOfFilterSupport) {
386 386
 				throw new \Exception('memberOf is not supported by the server');
@@ -400,7 +400,7 @@  discard block
 block discarded – undo
400 400
 
401 401
 		$filterParts = [];
402 402
 		foreach ($obclasses as $obclass) {
403
-			$filterParts[] = 'objectclass=' . $obclass;
403
+			$filterParts[] = 'objectclass='.$obclass;
404 404
 		}
405 405
 		//we filter for everything
406 406
 		//- that looks like a group and
@@ -645,7 +645,7 @@  discard block
 block discarded – undo
645 645
 			$p = $setting['port'];
646 646
 			$t = $setting['tls'];
647 647
 			$this->logger->debug(
648
-				'Wiz: trying port ' . $p . ', TLS ' . $t,
648
+				'Wiz: trying port '.$p.', TLS '.$t,
649 649
 				['app' => 'user_ldap']
650 650
 			);
651 651
 			//connectAndBind may throw Exception, it needs to be caught by the
@@ -666,12 +666,12 @@  discard block
 block discarded – undo
666 666
 
667 667
 			if ($settingsFound === true) {
668 668
 				$config = [
669
-					'ldapPort' => (string)$p,
670
-					'ldapTLS' => (string)$t,
669
+					'ldapPort' => (string) $p,
670
+					'ldapTLS' => (string) $t,
671 671
 				];
672 672
 				$this->configuration->setConfiguration($config);
673 673
 				$this->logger->debug(
674
-					'Wiz: detected Port ' . $p,
674
+					'Wiz: detected Port '.$p,
675 675
 					['app' => 'user_ldap']
676 676
 				);
677 677
 				$this->result->addChange('ldap_port', $p);
@@ -718,7 +718,7 @@  discard block
 block discarded – undo
718 718
 
719 719
 		$dparts = explode('.', $domain);
720 720
 		while (count($dparts) > 0) {
721
-			$base2 = 'dc=' . implode(',dc=', $dparts);
721
+			$base2 = 'dc='.implode(',dc=', $dparts);
722 722
 			if ($base !== $base2 && $this->testBaseDN($base2)) {
723 723
 				$this->applyFind('ldap_base', $base2);
724 724
 				return $this->result;
@@ -753,9 +753,9 @@  discard block
 block discarded – undo
753 753
 		//removes Port from Host
754 754
 		if (is_array($hostInfo) && isset($hostInfo['port'])) {
755 755
 			$port = $hostInfo['port'];
756
-			$host = str_replace(':' . $port, '', $host);
756
+			$host = str_replace(':'.$port, '', $host);
757 757
 			$this->applyFind('ldap_host', $host);
758
-			$this->applyFind('ldap_port', (string)$port);
758
+			$this->applyFind('ldap_port', (string) $port);
759 759
 		}
760 760
 	}
761 761
 
@@ -822,7 +822,7 @@  discard block
 block discarded – undo
822 822
 			$errorNo = $this->ldap->errno($cr);
823 823
 			$errorMsg = $this->ldap->error($cr);
824 824
 			$this->logger->info(
825
-				'Wiz: Could not search base ' . $base . ' Error ' . $errorNo . ': ' . $errorMsg,
825
+				'Wiz: Could not search base '.$base.' Error '.$errorNo.': '.$errorMsg,
826 826
 				['app' => 'user_ldap']
827 827
 			);
828 828
 			return false;
@@ -870,7 +870,7 @@  discard block
 block discarded – undo
870 870
 				if (is_array($objcs) && count($objcs) > 0) {
871 871
 					$filter .= '(|';
872 872
 					foreach ($objcs as $objc) {
873
-						$filter .= '(objectclass=' . ldap_escape($objc, '', LDAP_ESCAPE_FILTER) . ')';
873
+						$filter .= '(objectclass='.ldap_escape($objc, '', LDAP_ESCAPE_FILTER).')';
874 874
 					}
875 875
 					$filter .= ')';
876 876
 					$parts++;
@@ -886,7 +886,7 @@  discard block
 block discarded – undo
886 886
 						}
887 887
 						$base = $this->configuration->ldapBase[0];
888 888
 						foreach ($cns as $cn) {
889
-							$rr = $this->ldap->search($cr, $base, 'cn=' . ldap_escape($cn, '', LDAP_ESCAPE_FILTER), ['dn', 'primaryGroupToken']);
889
+							$rr = $this->ldap->search($cr, $base, 'cn='.ldap_escape($cn, '', LDAP_ESCAPE_FILTER), ['dn', 'primaryGroupToken']);
890 890
 							if (!$this->ldap->isResource($rr)) {
891 891
 								continue;
892 892
 							}
@@ -897,11 +897,11 @@  discard block
 block discarded – undo
897 897
 							if ($dn === false || $dn === '') {
898 898
 								continue;
899 899
 							}
900
-							$filterPart = '(memberof=' . ldap_escape($dn, '', LDAP_ESCAPE_FILTER) . ')';
900
+							$filterPart = '(memberof='.ldap_escape($dn, '', LDAP_ESCAPE_FILTER).')';
901 901
 							if (isset($attrs['primaryGroupToken'])) {
902 902
 								$pgt = $attrs['primaryGroupToken'][0];
903
-								$primaryFilterPart = '(primaryGroupID=' . ldap_escape($pgt, '', LDAP_ESCAPE_FILTER) . ')';
904
-								$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
903
+								$primaryFilterPart = '(primaryGroupID='.ldap_escape($pgt, '', LDAP_ESCAPE_FILTER).')';
904
+								$filterPart = '(|'.$filterPart.$primaryFilterPart.')';
905 905
 							}
906 906
 							$filter .= $filterPart;
907 907
 						}
@@ -911,7 +911,7 @@  discard block
 block discarded – undo
911 911
 				}
912 912
 				//wrap parts in AND condition
913 913
 				if ($parts > 1) {
914
-					$filter = '(&' . $filter . ')';
914
+					$filter = '(&'.$filter.')';
915 915
 				}
916 916
 				if ($filter === '') {
917 917
 					$filter = '(objectclass=*)';
@@ -924,7 +924,7 @@  discard block
 block discarded – undo
924 924
 				if (is_array($objcs) && count($objcs) > 0) {
925 925
 					$filter .= '(|';
926 926
 					foreach ($objcs as $objc) {
927
-						$filter .= '(objectclass=' . ldap_escape($objc, '', LDAP_ESCAPE_FILTER) . ')';
927
+						$filter .= '(objectclass='.ldap_escape($objc, '', LDAP_ESCAPE_FILTER).')';
928 928
 					}
929 929
 					$filter .= ')';
930 930
 					$parts++;
@@ -934,14 +934,14 @@  discard block
 block discarded – undo
934 934
 				if (is_array($cns) && count($cns) > 0) {
935 935
 					$filter .= '(|';
936 936
 					foreach ($cns as $cn) {
937
-						$filter .= '(cn=' . ldap_escape($cn, '', LDAP_ESCAPE_FILTER) . ')';
937
+						$filter .= '(cn='.ldap_escape($cn, '', LDAP_ESCAPE_FILTER).')';
938 938
 					}
939 939
 					$filter .= ')';
940 940
 				}
941 941
 				$parts++;
942 942
 				//wrap parts in AND condition
943 943
 				if ($parts > 1) {
944
-					$filter = '(&' . $filter . ')';
944
+					$filter = '(&'.$filter.')';
945 945
 				}
946 946
 				break;
947 947
 
@@ -967,7 +967,7 @@  discard block
 block discarded – undo
967 967
 						$attr = 'cn';
968 968
 					}
969 969
 					if ($attr !== '') {
970
-						$filterUsername = '(' . $attr . $loginpart . ')';
970
+						$filterUsername = '('.$attr.$loginpart.')';
971 971
 						$parts++;
972 972
 					}
973 973
 				}
@@ -983,7 +983,7 @@  discard block
 block discarded – undo
983 983
 				if (is_array($attrsToFilter) && count($attrsToFilter) > 0) {
984 984
 					$filterAttributes = '(|';
985 985
 					foreach ($attrsToFilter as $attribute) {
986
-						$filterAttributes .= '(' . $attribute . $loginpart . ')';
986
+						$filterAttributes .= '('.$attribute.$loginpart.')';
987 987
 					}
988 988
 					$filterAttributes .= ')';
989 989
 					$parts++;
@@ -1000,12 +1000,12 @@  discard block
 block discarded – undo
1000 1000
 					$filterLogin .= ')';
1001 1001
 				}
1002 1002
 
1003
-				$filter = '(&' . $ulf . $filterLogin . ')';
1003
+				$filter = '(&'.$ulf.$filterLogin.')';
1004 1004
 				break;
1005 1005
 		}
1006 1006
 
1007 1007
 		$this->logger->debug(
1008
-			'Wiz: Final filter ' . $filter,
1008
+			'Wiz: Final filter '.$filter,
1009 1009
 			['app' => 'user_ldap']
1010 1010
 		);
1011 1011
 
@@ -1022,7 +1022,7 @@  discard block
 block discarded – undo
1022 1022
 	private function connectAndBind(int $port, bool $tls): bool {
1023 1023
 		//connect, does not really trigger any server communication
1024 1024
 		$host = $this->configuration->ldapHost;
1025
-		$hostInfo = parse_url((string)$host);
1025
+		$hostInfo = parse_url((string) $host);
1026 1026
 		if (!is_string($host) || !$hostInfo) {
1027 1027
 			throw new \Exception(self::$l->t('Invalid Host'));
1028 1028
 		}
@@ -1030,7 +1030,7 @@  discard block
 block discarded – undo
1030 1030
 			'Wiz: Attempting to connect',
1031 1031
 			['app' => 'user_ldap']
1032 1032
 		);
1033
-		$cr = $this->ldap->connect($host, (string)$port);
1033
+		$cr = $this->ldap->connect($host, (string) $port);
1034 1034
 		if (!$this->ldap->isResource($cr)) {
1035 1035
 			throw new \Exception(self::$l->t('Invalid Host'));
1036 1036
 		}
@@ -1067,7 +1067,7 @@  discard block
 block discarded – undo
1067 1067
 
1068 1068
 		if ($login === true) {
1069 1069
 			$this->logger->debug(
1070
-				'Wiz: Bind successful to Port ' . $port . ' TLS ' . (int)$tls,
1070
+				'Wiz: Bind successful to Port '.$port.' TLS '.(int) $tls,
1071 1071
 				['app' => 'user_ldap']
1072 1072
 			);
1073 1073
 			return true;
@@ -1201,7 +1201,7 @@  discard block
 block discarded – undo
1201 1201
 		}
1202 1202
 		$p = 'objectclass=';
1203 1203
 		foreach ($objectclasses as $key => $value) {
1204
-			$objectclasses[$key] = $p . $value;
1204
+			$objectclasses[$key] = $p.$value;
1205 1205
 		}
1206 1206
 		$maxEntryObjC = '';
1207 1207
 
@@ -1271,7 +1271,7 @@  discard block
 block discarded – undo
1271 1271
 	/**
1272 1272
 	 * @return \LDAP\Connection|false a link resource on success, otherwise false
1273 1273
 	 */
1274
-	private function getConnection(): \LDAP\Connection|false {
1274
+	private function getConnection(): \LDAP\Connection | false {
1275 1275
 		if (!is_null($this->cr)) {
1276 1276
 			return $this->cr;
1277 1277
 		}
@@ -1326,7 +1326,7 @@  discard block
 block discarded – undo
1326 1326
 		//636 ← LDAPS / SSL
1327 1327
 		//7xxx ← UCS. need to be checked first, because both ports may be open
1328 1328
 		$host = $this->configuration->ldapHost;
1329
-		$port = (int)$this->configuration->ldapPort;
1329
+		$port = (int) $this->configuration->ldapPort;
1330 1330
 		$portSettings = [];
1331 1331
 
1332 1332
 		//In case the port is already provided, we will check this first
Please login to merge, or discard this patch.
apps/user_ldap/lib/Controller/ConfigAPIController.php 1 patch
Indentation   +293 added lines, -293 removed lines patch added patch discarded remove patch
@@ -27,249 +27,249 @@  discard block
 block discarded – undo
27 27
 use Psr\Log\LoggerInterface;
28 28
 
29 29
 class ConfigAPIController extends OCSController {
30
-	public function __construct(
31
-		string $appName,
32
-		IRequest $request,
33
-		private Helper $ldapHelper,
34
-		private LoggerInterface $logger,
35
-		private ConnectionFactory $connectionFactory,
36
-		private IL10N $l,
37
-	) {
38
-		parent::__construct($appName, $request);
39
-	}
30
+    public function __construct(
31
+        string $appName,
32
+        IRequest $request,
33
+        private Helper $ldapHelper,
34
+        private LoggerInterface $logger,
35
+        private ConnectionFactory $connectionFactory,
36
+        private IL10N $l,
37
+    ) {
38
+        parent::__construct($appName, $request);
39
+    }
40 40
 
41
-	/**
42
-	 * Create a new (empty) configuration and return the resulting prefix
43
-	 *
44
-	 * @return DataResponse<Http::STATUS_OK, array{configID: string}, array{}>
45
-	 * @throws OCSException
46
-	 *
47
-	 * 200: Config created successfully
48
-	 */
49
-	#[AuthorizedAdminSetting(settings: Admin::class)]
50
-	#[ApiRoute(verb: 'POST', url: '/api/v1/config')]
51
-	public function create() {
52
-		try {
53
-			$configPrefix = $this->ldapHelper->getNextServerConfigurationPrefix();
54
-			$configHolder = new Configuration($configPrefix);
55
-			$configHolder->ldapConfigurationActive = false;
56
-			$configHolder->saveConfiguration();
57
-		} catch (\Exception $e) {
58
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
59
-			throw new OCSException('An issue occurred when creating the new config.');
60
-		}
61
-		return new DataResponse(['configID' => $configPrefix]);
62
-	}
41
+    /**
42
+     * Create a new (empty) configuration and return the resulting prefix
43
+     *
44
+     * @return DataResponse<Http::STATUS_OK, array{configID: string}, array{}>
45
+     * @throws OCSException
46
+     *
47
+     * 200: Config created successfully
48
+     */
49
+    #[AuthorizedAdminSetting(settings: Admin::class)]
50
+    #[ApiRoute(verb: 'POST', url: '/api/v1/config')]
51
+    public function create() {
52
+        try {
53
+            $configPrefix = $this->ldapHelper->getNextServerConfigurationPrefix();
54
+            $configHolder = new Configuration($configPrefix);
55
+            $configHolder->ldapConfigurationActive = false;
56
+            $configHolder->saveConfiguration();
57
+        } catch (\Exception $e) {
58
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
59
+            throw new OCSException('An issue occurred when creating the new config.');
60
+        }
61
+        return new DataResponse(['configID' => $configPrefix]);
62
+    }
63 63
 
64
-	/**
65
-	 * Delete a LDAP configuration
66
-	 *
67
-	 * @param string $configID ID of the config
68
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
69
-	 * @throws OCSException
70
-	 * @throws OCSNotFoundException Config not found
71
-	 *
72
-	 * 200: Config deleted successfully
73
-	 */
74
-	#[AuthorizedAdminSetting(settings: Admin::class)]
75
-	#[ApiRoute(verb: 'DELETE', url: '/api/v1/config/{configID}')]
76
-	public function delete($configID) {
77
-		try {
78
-			$this->ensureConfigIDExists($configID);
79
-			if (!$this->ldapHelper->deleteServerConfiguration($configID)) {
80
-				throw new OCSException('Could not delete configuration');
81
-			}
82
-		} catch (OCSException $e) {
83
-			throw $e;
84
-		} catch (\Exception $e) {
85
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
86
-			throw new OCSException('An issue occurred when deleting the config.');
87
-		}
64
+    /**
65
+     * Delete a LDAP configuration
66
+     *
67
+     * @param string $configID ID of the config
68
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
69
+     * @throws OCSException
70
+     * @throws OCSNotFoundException Config not found
71
+     *
72
+     * 200: Config deleted successfully
73
+     */
74
+    #[AuthorizedAdminSetting(settings: Admin::class)]
75
+    #[ApiRoute(verb: 'DELETE', url: '/api/v1/config/{configID}')]
76
+    public function delete($configID) {
77
+        try {
78
+            $this->ensureConfigIDExists($configID);
79
+            if (!$this->ldapHelper->deleteServerConfiguration($configID)) {
80
+                throw new OCSException('Could not delete configuration');
81
+            }
82
+        } catch (OCSException $e) {
83
+            throw $e;
84
+        } catch (\Exception $e) {
85
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
86
+            throw new OCSException('An issue occurred when deleting the config.');
87
+        }
88 88
 
89
-		return new DataResponse();
90
-	}
89
+        return new DataResponse();
90
+    }
91 91
 
92
-	/**
93
-	 * Modify a configuration
94
-	 *
95
-	 * @param string $configID ID of the config
96
-	 * @param array<string, mixed> $configData New config
97
-	 * @return DataResponse<Http::STATUS_OK, array<string, mixed>, array{}>
98
-	 * @throws OCSException
99
-	 * @throws OCSBadRequestException Modifying config is not possible
100
-	 * @throws OCSNotFoundException Config not found
101
-	 *
102
-	 * 200: Config returned
103
-	 */
104
-	#[AuthorizedAdminSetting(settings: Admin::class)]
105
-	#[ApiRoute(verb: 'PUT', url: '/api/v1/config/{configID}')]
106
-	public function modify($configID, $configData) {
107
-		try {
108
-			$this->ensureConfigIDExists($configID);
92
+    /**
93
+     * Modify a configuration
94
+     *
95
+     * @param string $configID ID of the config
96
+     * @param array<string, mixed> $configData New config
97
+     * @return DataResponse<Http::STATUS_OK, array<string, mixed>, array{}>
98
+     * @throws OCSException
99
+     * @throws OCSBadRequestException Modifying config is not possible
100
+     * @throws OCSNotFoundException Config not found
101
+     *
102
+     * 200: Config returned
103
+     */
104
+    #[AuthorizedAdminSetting(settings: Admin::class)]
105
+    #[ApiRoute(verb: 'PUT', url: '/api/v1/config/{configID}')]
106
+    public function modify($configID, $configData) {
107
+        try {
108
+            $this->ensureConfigIDExists($configID);
109 109
 
110
-			if (!is_array($configData)) {
111
-				throw new OCSBadRequestException('configData is not properly set');
112
-			}
110
+            if (!is_array($configData)) {
111
+                throw new OCSBadRequestException('configData is not properly set');
112
+            }
113 113
 
114
-			$configuration = new Configuration($configID);
115
-			$configKeys = $configuration->getConfigTranslationArray();
114
+            $configuration = new Configuration($configID);
115
+            $configKeys = $configuration->getConfigTranslationArray();
116 116
 
117
-			foreach ($configKeys as $i => $key) {
118
-				if (isset($configData[$key])) {
119
-					$configuration->$key = $configData[$key];
120
-				}
121
-			}
117
+            foreach ($configKeys as $i => $key) {
118
+                if (isset($configData[$key])) {
119
+                    $configuration->$key = $configData[$key];
120
+                }
121
+            }
122 122
 
123
-			$configuration->saveConfiguration();
124
-			$this->connectionFactory->get($configID)->clearCache();
125
-		} catch (OCSException $e) {
126
-			throw $e;
127
-		} catch (\Exception $e) {
128
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
129
-			throw new OCSException('An issue occurred when modifying the config.');
130
-		}
123
+            $configuration->saveConfiguration();
124
+            $this->connectionFactory->get($configID)->clearCache();
125
+        } catch (OCSException $e) {
126
+            throw $e;
127
+        } catch (\Exception $e) {
128
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
129
+            throw new OCSException('An issue occurred when modifying the config.');
130
+        }
131 131
 
132
-		return $this->show($configID, false);
133
-	}
132
+        return $this->show($configID, false);
133
+    }
134 134
 
135
-	/**
136
-	 * Get a configuration
137
-	 *
138
-	 * Output can look like this:
139
-	 * <?xml version="1.0"?>
140
-	 * <ocs>
141
-	 *   <meta>
142
-	 *     <status>ok</status>
143
-	 *     <statuscode>200</statuscode>
144
-	 *     <message>OK</message>
145
-	 *   </meta>
146
-	 *   <data>
147
-	 *     <ldapHost>ldaps://my.ldap.server</ldapHost>
148
-	 *     <ldapPort>7770</ldapPort>
149
-	 *     <ldapBackupHost></ldapBackupHost>
150
-	 *     <ldapBackupPort></ldapBackupPort>
151
-	 *     <ldapBase>ou=small,dc=my,dc=ldap,dc=server</ldapBase>
152
-	 *     <ldapBaseUsers>ou=users,ou=small,dc=my,dc=ldap,dc=server</ldapBaseUsers>
153
-	 *     <ldapBaseGroups>ou=small,dc=my,dc=ldap,dc=server</ldapBaseGroups>
154
-	 *     <ldapAgentName>cn=root,dc=my,dc=ldap,dc=server</ldapAgentName>
155
-	 *     <ldapAgentPassword>clearTextWithShowPassword=1</ldapAgentPassword>
156
-	 *     <ldapTLS>1</ldapTLS>
157
-	 *     <turnOffCertCheck>0</turnOffCertCheck>
158
-	 *     <ldapIgnoreNamingRules/>
159
-	 *     <ldapUserDisplayName>displayname</ldapUserDisplayName>
160
-	 *     <ldapUserDisplayName2>uid</ldapUserDisplayName2>
161
-	 *     <ldapUserFilterObjectclass>inetOrgPerson</ldapUserFilterObjectclass>
162
-	 *     <ldapUserFilterGroups></ldapUserFilterGroups>
163
-	 *     <ldapUserFilter>(&amp;(objectclass=nextcloudUser)(nextcloudEnabled=TRUE))</ldapUserFilter>
164
-	 *     <ldapUserFilterMode>1</ldapUserFilterMode>
165
-	 *     <ldapGroupFilter>(&amp;(|(objectclass=nextcloudGroup)))</ldapGroupFilter>
166
-	 *     <ldapGroupFilterMode>0</ldapGroupFilterMode>
167
-	 *     <ldapGroupFilterObjectclass>nextcloudGroup</ldapGroupFilterObjectclass>
168
-	 *     <ldapGroupFilterGroups></ldapGroupFilterGroups>
169
-	 *     <ldapGroupDisplayName>cn</ldapGroupDisplayName>
170
-	 *     <ldapGroupMemberAssocAttr>memberUid</ldapGroupMemberAssocAttr>
171
-	 *     <ldapLoginFilter>(&amp;(|(objectclass=inetOrgPerson))(uid=%uid))</ldapLoginFilter>
172
-	 *     <ldapLoginFilterMode>0</ldapLoginFilterMode>
173
-	 *     <ldapLoginFilterEmail>0</ldapLoginFilterEmail>
174
-	 *     <ldapLoginFilterUsername>1</ldapLoginFilterUsername>
175
-	 *     <ldapLoginFilterAttributes></ldapLoginFilterAttributes>
176
-	 *     <ldapQuotaAttribute></ldapQuotaAttribute>
177
-	 *     <ldapQuotaDefault></ldapQuotaDefault>
178
-	 *     <ldapEmailAttribute>mail</ldapEmailAttribute>
179
-	 *     <ldapCacheTTL>20</ldapCacheTTL>
180
-	 *     <ldapUuidUserAttribute>auto</ldapUuidUserAttribute>
181
-	 *     <ldapUuidGroupAttribute>auto</ldapUuidGroupAttribute>
182
-	 *     <ldapOverrideMainServer></ldapOverrideMainServer>
183
-	 *     <ldapConfigurationActive>1</ldapConfigurationActive>
184
-	 *     <ldapAttributesForUserSearch>uid;sn;givenname</ldapAttributesForUserSearch>
185
-	 *     <ldapAttributesForGroupSearch></ldapAttributesForGroupSearch>
186
-	 *     <ldapExperiencedAdmin>0</ldapExperiencedAdmin>
187
-	 *     <homeFolderNamingRule></homeFolderNamingRule>
188
-	 *     <hasMemberOfFilterSupport></hasMemberOfFilterSupport>
189
-	 *     <useMemberOfToDetectMembership>1</useMemberOfToDetectMembership>
190
-	 *     <ldapExpertUsernameAttr>uid</ldapExpertUsernameAttr>
191
-	 *     <ldapExpertUUIDUserAttr>uid</ldapExpertUUIDUserAttr>
192
-	 *     <ldapExpertUUIDGroupAttr></ldapExpertUUIDGroupAttr>
193
-	 *     <lastJpegPhotoLookup>0</lastJpegPhotoLookup>
194
-	 *     <ldapNestedGroups>0</ldapNestedGroups>
195
-	 *     <ldapPagingSize>500</ldapPagingSize>
196
-	 *     <turnOnPasswordChange>1</turnOnPasswordChange>
197
-	 *     <ldapDynamicGroupMemberURL></ldapDynamicGroupMemberURL>
198
-	 *   </data>
199
-	 * </ocs>
200
-	 *
201
-	 * @param string $configID ID of the config
202
-	 * @param bool $showPassword Whether to show the password
203
-	 * @return DataResponse<Http::STATUS_OK, array<string, mixed>, array{}>
204
-	 * @throws OCSException
205
-	 * @throws OCSNotFoundException Config not found
206
-	 *
207
-	 * 200: Config returned
208
-	 */
209
-	#[AuthorizedAdminSetting(settings: Admin::class)]
210
-	#[ApiRoute(verb: 'GET', url: '/api/v1/config/{configID}')]
211
-	public function show($configID, $showPassword = false) {
212
-		try {
213
-			$this->ensureConfigIDExists($configID);
135
+    /**
136
+     * Get a configuration
137
+     *
138
+     * Output can look like this:
139
+     * <?xml version="1.0"?>
140
+     * <ocs>
141
+     *   <meta>
142
+     *     <status>ok</status>
143
+     *     <statuscode>200</statuscode>
144
+     *     <message>OK</message>
145
+     *   </meta>
146
+     *   <data>
147
+     *     <ldapHost>ldaps://my.ldap.server</ldapHost>
148
+     *     <ldapPort>7770</ldapPort>
149
+     *     <ldapBackupHost></ldapBackupHost>
150
+     *     <ldapBackupPort></ldapBackupPort>
151
+     *     <ldapBase>ou=small,dc=my,dc=ldap,dc=server</ldapBase>
152
+     *     <ldapBaseUsers>ou=users,ou=small,dc=my,dc=ldap,dc=server</ldapBaseUsers>
153
+     *     <ldapBaseGroups>ou=small,dc=my,dc=ldap,dc=server</ldapBaseGroups>
154
+     *     <ldapAgentName>cn=root,dc=my,dc=ldap,dc=server</ldapAgentName>
155
+     *     <ldapAgentPassword>clearTextWithShowPassword=1</ldapAgentPassword>
156
+     *     <ldapTLS>1</ldapTLS>
157
+     *     <turnOffCertCheck>0</turnOffCertCheck>
158
+     *     <ldapIgnoreNamingRules/>
159
+     *     <ldapUserDisplayName>displayname</ldapUserDisplayName>
160
+     *     <ldapUserDisplayName2>uid</ldapUserDisplayName2>
161
+     *     <ldapUserFilterObjectclass>inetOrgPerson</ldapUserFilterObjectclass>
162
+     *     <ldapUserFilterGroups></ldapUserFilterGroups>
163
+     *     <ldapUserFilter>(&amp;(objectclass=nextcloudUser)(nextcloudEnabled=TRUE))</ldapUserFilter>
164
+     *     <ldapUserFilterMode>1</ldapUserFilterMode>
165
+     *     <ldapGroupFilter>(&amp;(|(objectclass=nextcloudGroup)))</ldapGroupFilter>
166
+     *     <ldapGroupFilterMode>0</ldapGroupFilterMode>
167
+     *     <ldapGroupFilterObjectclass>nextcloudGroup</ldapGroupFilterObjectclass>
168
+     *     <ldapGroupFilterGroups></ldapGroupFilterGroups>
169
+     *     <ldapGroupDisplayName>cn</ldapGroupDisplayName>
170
+     *     <ldapGroupMemberAssocAttr>memberUid</ldapGroupMemberAssocAttr>
171
+     *     <ldapLoginFilter>(&amp;(|(objectclass=inetOrgPerson))(uid=%uid))</ldapLoginFilter>
172
+     *     <ldapLoginFilterMode>0</ldapLoginFilterMode>
173
+     *     <ldapLoginFilterEmail>0</ldapLoginFilterEmail>
174
+     *     <ldapLoginFilterUsername>1</ldapLoginFilterUsername>
175
+     *     <ldapLoginFilterAttributes></ldapLoginFilterAttributes>
176
+     *     <ldapQuotaAttribute></ldapQuotaAttribute>
177
+     *     <ldapQuotaDefault></ldapQuotaDefault>
178
+     *     <ldapEmailAttribute>mail</ldapEmailAttribute>
179
+     *     <ldapCacheTTL>20</ldapCacheTTL>
180
+     *     <ldapUuidUserAttribute>auto</ldapUuidUserAttribute>
181
+     *     <ldapUuidGroupAttribute>auto</ldapUuidGroupAttribute>
182
+     *     <ldapOverrideMainServer></ldapOverrideMainServer>
183
+     *     <ldapConfigurationActive>1</ldapConfigurationActive>
184
+     *     <ldapAttributesForUserSearch>uid;sn;givenname</ldapAttributesForUserSearch>
185
+     *     <ldapAttributesForGroupSearch></ldapAttributesForGroupSearch>
186
+     *     <ldapExperiencedAdmin>0</ldapExperiencedAdmin>
187
+     *     <homeFolderNamingRule></homeFolderNamingRule>
188
+     *     <hasMemberOfFilterSupport></hasMemberOfFilterSupport>
189
+     *     <useMemberOfToDetectMembership>1</useMemberOfToDetectMembership>
190
+     *     <ldapExpertUsernameAttr>uid</ldapExpertUsernameAttr>
191
+     *     <ldapExpertUUIDUserAttr>uid</ldapExpertUUIDUserAttr>
192
+     *     <ldapExpertUUIDGroupAttr></ldapExpertUUIDGroupAttr>
193
+     *     <lastJpegPhotoLookup>0</lastJpegPhotoLookup>
194
+     *     <ldapNestedGroups>0</ldapNestedGroups>
195
+     *     <ldapPagingSize>500</ldapPagingSize>
196
+     *     <turnOnPasswordChange>1</turnOnPasswordChange>
197
+     *     <ldapDynamicGroupMemberURL></ldapDynamicGroupMemberURL>
198
+     *   </data>
199
+     * </ocs>
200
+     *
201
+     * @param string $configID ID of the config
202
+     * @param bool $showPassword Whether to show the password
203
+     * @return DataResponse<Http::STATUS_OK, array<string, mixed>, array{}>
204
+     * @throws OCSException
205
+     * @throws OCSNotFoundException Config not found
206
+     *
207
+     * 200: Config returned
208
+     */
209
+    #[AuthorizedAdminSetting(settings: Admin::class)]
210
+    #[ApiRoute(verb: 'GET', url: '/api/v1/config/{configID}')]
211
+    public function show($configID, $showPassword = false) {
212
+        try {
213
+            $this->ensureConfigIDExists($configID);
214 214
 
215
-			$config = new Configuration($configID);
216
-			$data = $config->getConfiguration();
217
-			if (!$showPassword) {
218
-				$data['ldapAgentPassword'] = '***';
219
-			}
220
-			foreach ($data as $key => $value) {
221
-				if (is_array($value)) {
222
-					$value = implode(';', $value);
223
-					$data[$key] = $value;
224
-				}
225
-			}
226
-		} catch (OCSException $e) {
227
-			throw $e;
228
-		} catch (\Exception $e) {
229
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
230
-			throw new OCSException('An issue occurred when modifying the config.');
231
-		}
215
+            $config = new Configuration($configID);
216
+            $data = $config->getConfiguration();
217
+            if (!$showPassword) {
218
+                $data['ldapAgentPassword'] = '***';
219
+            }
220
+            foreach ($data as $key => $value) {
221
+                if (is_array($value)) {
222
+                    $value = implode(';', $value);
223
+                    $data[$key] = $value;
224
+                }
225
+            }
226
+        } catch (OCSException $e) {
227
+            throw $e;
228
+        } catch (\Exception $e) {
229
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
230
+            throw new OCSException('An issue occurred when modifying the config.');
231
+        }
232 232
 
233
-		return new DataResponse($data);
234
-	}
233
+        return new DataResponse($data);
234
+    }
235 235
 
236
-	/**
237
-	 * Test a configuration
238
-	 *
239
-	 * @param string $configID ID of the LDAP config
240
-	 * @return DataResponse<Http::STATUS_OK, array{success:bool,message:string}, array{}>
241
-	 * @throws OCSException An unexpected error happened
242
-	 * @throws OCSNotFoundException Config not found
243
-	 *
244
-	 * 200: Test was run and results are returned
245
-	 */
246
-	#[AuthorizedAdminSetting(settings: Admin::class)]
247
-	#[ApiRoute(verb: 'POST', url: '/api/v1/config/{configID}/test')]
248
-	public function testConfiguration(string $configID) {
249
-		try {
250
-			$this->ensureConfigIDExists($configID);
251
-			$connection = $this->connectionFactory->get($configID);
252
-			$conf = $connection->getConfiguration();
253
-			if ($conf['ldap_configuration_active'] === '0') {
254
-				//needs to be true, otherwise it will also fail with an irritating message
255
-				$conf['ldap_configuration_active'] = '1';
256
-			}
257
-			try {
258
-				$connection->setConfiguration($conf, throw: true);
259
-			} catch (ConfigurationIssueException $e) {
260
-				return new DataResponse([
261
-					'success' => false,
262
-					'message' => $this->l->t('Invalid configuration: %s', $e->getHint()),
263
-				]);
264
-			}
265
-			// Configuration is okay
266
-			if (!$connection->bind()) {
267
-				return new DataResponse([
268
-					'success' => false,
269
-					'message' => $this->l->t('Valid configuration, but binding failed. Please check the server settings and credentials.'),
270
-				]);
271
-			}
272
-			/*
236
+    /**
237
+     * Test a configuration
238
+     *
239
+     * @param string $configID ID of the LDAP config
240
+     * @return DataResponse<Http::STATUS_OK, array{success:bool,message:string}, array{}>
241
+     * @throws OCSException An unexpected error happened
242
+     * @throws OCSNotFoundException Config not found
243
+     *
244
+     * 200: Test was run and results are returned
245
+     */
246
+    #[AuthorizedAdminSetting(settings: Admin::class)]
247
+    #[ApiRoute(verb: 'POST', url: '/api/v1/config/{configID}/test')]
248
+    public function testConfiguration(string $configID) {
249
+        try {
250
+            $this->ensureConfigIDExists($configID);
251
+            $connection = $this->connectionFactory->get($configID);
252
+            $conf = $connection->getConfiguration();
253
+            if ($conf['ldap_configuration_active'] === '0') {
254
+                //needs to be true, otherwise it will also fail with an irritating message
255
+                $conf['ldap_configuration_active'] = '1';
256
+            }
257
+            try {
258
+                $connection->setConfiguration($conf, throw: true);
259
+            } catch (ConfigurationIssueException $e) {
260
+                return new DataResponse([
261
+                    'success' => false,
262
+                    'message' => $this->l->t('Invalid configuration: %s', $e->getHint()),
263
+                ]);
264
+            }
265
+            // Configuration is okay
266
+            if (!$connection->bind()) {
267
+                return new DataResponse([
268
+                    'success' => false,
269
+                    'message' => $this->l->t('Valid configuration, but binding failed. Please check the server settings and credentials.'),
270
+                ]);
271
+            }
272
+            /*
273 273
 			* This shiny if block is an ugly hack to find out whether anonymous
274 274
 			* bind is possible on AD or not. Because AD happily and constantly
275 275
 			* replies with success to any anonymous bind request, we need to
@@ -278,69 +278,69 @@  discard block
 block discarded – undo
278 278
 			* exception by the LDAP wrapper. We catch this. Other cases may
279 279
 			* pass (like e.g. expected syntax error).
280 280
 			*/
281
-			try {
282
-				$ldapWrapper = Server::get(ILDAPWrapper::class);
283
-				$ldapWrapper->read($connection->getConnectionResource(), '', 'objectClass=*', ['dn']);
284
-			} catch (\Exception $e) {
285
-				if ($e->getCode() === 1) {
286
-					return new DataResponse([
287
-						'success' => false,
288
-						'message' => $this->l->t('Invalid configuration: Anonymous binding is not allowed.'),
289
-					]);
290
-				}
291
-			}
292
-			return new DataResponse([
293
-				'success' => true,
294
-				'message' => $this->l->t('Valid configuration, connection established!'),
295
-			]);
296
-		} catch (OCSException $e) {
297
-			throw $e;
298
-		} catch (\Exception $e) {
299
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
300
-			throw new OCSException('An issue occurred when testing the config.');
301
-		}
302
-	}
281
+            try {
282
+                $ldapWrapper = Server::get(ILDAPWrapper::class);
283
+                $ldapWrapper->read($connection->getConnectionResource(), '', 'objectClass=*', ['dn']);
284
+            } catch (\Exception $e) {
285
+                if ($e->getCode() === 1) {
286
+                    return new DataResponse([
287
+                        'success' => false,
288
+                        'message' => $this->l->t('Invalid configuration: Anonymous binding is not allowed.'),
289
+                    ]);
290
+                }
291
+            }
292
+            return new DataResponse([
293
+                'success' => true,
294
+                'message' => $this->l->t('Valid configuration, connection established!'),
295
+            ]);
296
+        } catch (OCSException $e) {
297
+            throw $e;
298
+        } catch (\Exception $e) {
299
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
300
+            throw new OCSException('An issue occurred when testing the config.');
301
+        }
302
+    }
303 303
 
304
-	/**
305
-	 * Copy a configuration
306
-	 *
307
-	 * @param string $configID ID of the LDAP config
308
-	 * @return DataResponse<Http::STATUS_OK, array{configID:string}, array{}>
309
-	 * @throws OCSException An unexpected error happened
310
-	 * @throws OCSNotFoundException Config not found
311
-	 *
312
-	 * 200: Config was copied, new configID was returned
313
-	 */
314
-	#[AuthorizedAdminSetting(settings: Admin::class)]
315
-	#[ApiRoute(verb: 'POST', url: '/api/v1/config/{configID}/copy')]
316
-	public function copyConfiguration(string $configID) {
317
-		try {
318
-			$this->ensureConfigIDExists($configID);
319
-			$configPrefix = $this->ldapHelper->getNextServerConfigurationPrefix();
320
-			$newConfig = new Configuration($configPrefix, false);
321
-			$originalConfig = new Configuration($configID);
322
-			$newConfig->setConfiguration($originalConfig->getConfiguration());
323
-			$newConfig->saveConfiguration();
324
-			return new DataResponse(['configID' => $configPrefix]);
325
-		} catch (OCSException $e) {
326
-			throw $e;
327
-		} catch (\Exception $e) {
328
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
329
-			throw new OCSException('An issue occurred when creating the new config.');
330
-		}
331
-	}
304
+    /**
305
+     * Copy a configuration
306
+     *
307
+     * @param string $configID ID of the LDAP config
308
+     * @return DataResponse<Http::STATUS_OK, array{configID:string}, array{}>
309
+     * @throws OCSException An unexpected error happened
310
+     * @throws OCSNotFoundException Config not found
311
+     *
312
+     * 200: Config was copied, new configID was returned
313
+     */
314
+    #[AuthorizedAdminSetting(settings: Admin::class)]
315
+    #[ApiRoute(verb: 'POST', url: '/api/v1/config/{configID}/copy')]
316
+    public function copyConfiguration(string $configID) {
317
+        try {
318
+            $this->ensureConfigIDExists($configID);
319
+            $configPrefix = $this->ldapHelper->getNextServerConfigurationPrefix();
320
+            $newConfig = new Configuration($configPrefix, false);
321
+            $originalConfig = new Configuration($configID);
322
+            $newConfig->setConfiguration($originalConfig->getConfiguration());
323
+            $newConfig->saveConfiguration();
324
+            return new DataResponse(['configID' => $configPrefix]);
325
+        } catch (OCSException $e) {
326
+            throw $e;
327
+        } catch (\Exception $e) {
328
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
329
+            throw new OCSException('An issue occurred when creating the new config.');
330
+        }
331
+    }
332 332
 
333
-	/**
334
-	 * If the given config ID is not available, an exception is thrown
335
-	 *
336
-	 * @param string $configID
337
-	 * @throws OCSNotFoundException
338
-	 */
339
-	#[AuthorizedAdminSetting(settings: Admin::class)]
340
-	private function ensureConfigIDExists($configID): void {
341
-		$prefixes = $this->ldapHelper->getServerConfigurationPrefixes();
342
-		if (!in_array($configID, $prefixes, true)) {
343
-			throw new OCSNotFoundException('Config ID not found');
344
-		}
345
-	}
333
+    /**
334
+     * If the given config ID is not available, an exception is thrown
335
+     *
336
+     * @param string $configID
337
+     * @throws OCSNotFoundException
338
+     */
339
+    #[AuthorizedAdminSetting(settings: Admin::class)]
340
+    private function ensureConfigIDExists($configID): void {
341
+        $prefixes = $this->ldapHelper->getServerConfigurationPrefixes();
342
+        if (!in_array($configID, $prefixes, true)) {
343
+            throw new OCSNotFoundException('Config ID not found');
344
+        }
345
+    }
346 346
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Controller/WizardController.php 2 patches
Indentation   +125 added lines, -125 removed lines patch added patch discarded remove patch
@@ -31,134 +31,134 @@
 block discarded – undo
31 31
 use Psr\Log\LoggerInterface;
32 32
 
33 33
 class WizardController extends OCSController {
34
-	public function __construct(
35
-		string $appName,
36
-		IRequest $request,
37
-		private LoggerInterface $logger,
38
-		private ConnectionFactory $connectionFactory,
39
-		private IL10N $l,
40
-		private WizardFactory $wizardFactory,
41
-		private IEventDispatcher $eventDispatcher,
42
-	) {
43
-		parent::__construct($appName, $request);
44
-	}
34
+    public function __construct(
35
+        string $appName,
36
+        IRequest $request,
37
+        private LoggerInterface $logger,
38
+        private ConnectionFactory $connectionFactory,
39
+        private IL10N $l,
40
+        private WizardFactory $wizardFactory,
41
+        private IEventDispatcher $eventDispatcher,
42
+    ) {
43
+        parent::__construct($appName, $request);
44
+    }
45 45
 
46
-	/**
47
-	 * Run a wizard action and returns the result
48
-	 *
49
-	 * @param string $configID ID of the LDAP configuration
50
-	 * @param string $wizardAction Wizard action to run
51
-	 * @param ?string $loginName Login name to test for testLoginName action
52
-	 * @return DataResponse<Http::STATUS_OK, array{changes:array<string,int|string|list<int>|list<string>>,options?:array<string,list<string>>}, array{}>
53
-	 * @throws OCSException
54
-	 *
55
-	 * 200: Wizard action result
56
-	 */
57
-	#[AuthorizedAdminSetting(settings: Admin::class)]
58
-	#[ApiRoute(verb: 'POST', url: '/api/v1/wizard/{configID}/{wizardAction}')]
59
-	public function action(
60
-		string $configID, string $wizardAction,
61
-		?string $loginName = null,
62
-	) {
63
-		try {
64
-			$wizard = $this->wizardFactory->get($configID);
65
-			switch ($wizardAction) {
66
-				case 'guessPortAndTLS':
67
-				case 'guessBaseDN':
68
-				case 'detectEmailAttribute':
69
-				case 'detectUserDisplayNameAttribute':
70
-				case 'determineGroupMemberAssoc':
71
-				case 'determineUserObjectClasses':
72
-				case 'determineGroupObjectClasses':
73
-				case 'determineGroupsForUsers':
74
-				case 'determineGroupsForGroups':
75
-				case 'determineAttributes':
76
-				case 'getUserListFilter':
77
-				case 'getUserLoginFilter':
78
-				case 'getGroupFilter':
79
-				case 'countUsers':
80
-				case 'countGroups':
81
-				case 'countInBaseDN':
82
-					try {
83
-						$result = $wizard->$wizardAction();
84
-						if ($result !== false) {
85
-							return new DataResponse($result->getResultArray());
86
-						}
87
-					} catch (\Exception $e) {
88
-						throw new OCSException($e->getMessage());
89
-					}
90
-					throw new OCSException();
46
+    /**
47
+     * Run a wizard action and returns the result
48
+     *
49
+     * @param string $configID ID of the LDAP configuration
50
+     * @param string $wizardAction Wizard action to run
51
+     * @param ?string $loginName Login name to test for testLoginName action
52
+     * @return DataResponse<Http::STATUS_OK, array{changes:array<string,int|string|list<int>|list<string>>,options?:array<string,list<string>>}, array{}>
53
+     * @throws OCSException
54
+     *
55
+     * 200: Wizard action result
56
+     */
57
+    #[AuthorizedAdminSetting(settings: Admin::class)]
58
+    #[ApiRoute(verb: 'POST', url: '/api/v1/wizard/{configID}/{wizardAction}')]
59
+    public function action(
60
+        string $configID, string $wizardAction,
61
+        ?string $loginName = null,
62
+    ) {
63
+        try {
64
+            $wizard = $this->wizardFactory->get($configID);
65
+            switch ($wizardAction) {
66
+                case 'guessPortAndTLS':
67
+                case 'guessBaseDN':
68
+                case 'detectEmailAttribute':
69
+                case 'detectUserDisplayNameAttribute':
70
+                case 'determineGroupMemberAssoc':
71
+                case 'determineUserObjectClasses':
72
+                case 'determineGroupObjectClasses':
73
+                case 'determineGroupsForUsers':
74
+                case 'determineGroupsForGroups':
75
+                case 'determineAttributes':
76
+                case 'getUserListFilter':
77
+                case 'getUserLoginFilter':
78
+                case 'getGroupFilter':
79
+                case 'countUsers':
80
+                case 'countGroups':
81
+                case 'countInBaseDN':
82
+                    try {
83
+                        $result = $wizard->$wizardAction();
84
+                        if ($result !== false) {
85
+                            return new DataResponse($result->getResultArray());
86
+                        }
87
+                    } catch (\Exception $e) {
88
+                        throw new OCSException($e->getMessage());
89
+                    }
90
+                    throw new OCSException();
91 91
 
92
-				case 'testLoginName':
93
-					try {
94
-						if ($loginName === null || $loginName === '') {
95
-							throw new OCSException('No login name passed');
96
-						}
97
-						$result = $wizard->$wizardAction($loginName);
98
-						if ($result !== false) {
99
-							return new DataResponse($result->getResultArray());
100
-						}
101
-					} catch (\Exception $e) {
102
-						throw new OCSException($e->getMessage());
103
-					}
104
-					throw new OCSException();
92
+                case 'testLoginName':
93
+                    try {
94
+                        if ($loginName === null || $loginName === '') {
95
+                            throw new OCSException('No login name passed');
96
+                        }
97
+                        $result = $wizard->$wizardAction($loginName);
98
+                        if ($result !== false) {
99
+                            return new DataResponse($result->getResultArray());
100
+                        }
101
+                    } catch (\Exception $e) {
102
+                        throw new OCSException($e->getMessage());
103
+                    }
104
+                    throw new OCSException();
105 105
 
106
-				default:
107
-					throw new OCSException($this->l->t('Action does not exist'));
108
-					break;
109
-			}
110
-		} catch (OCSException $e) {
111
-			throw $e;
112
-		} catch (\Exception $e) {
113
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
114
-			throw new OCSException('An issue occurred.');
115
-		}
116
-	}
106
+                default:
107
+                    throw new OCSException($this->l->t('Action does not exist'));
108
+                    break;
109
+            }
110
+        } catch (OCSException $e) {
111
+            throw $e;
112
+        } catch (\Exception $e) {
113
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
114
+            throw new OCSException('An issue occurred.');
115
+        }
116
+    }
117 117
 
118
-	/**
119
-	 * Clear user or group mappings
120
-	 *
121
-	 * @param 'user'|'group' $subject Whether to clear group or user mappings
122
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
123
-	 * @throws OCSException
124
-	 *
125
-	 * 200: Clearing was done successfuly
126
-	 */
127
-	#[AuthorizedAdminSetting(settings: Admin::class)]
128
-	#[ApiRoute(verb: 'POST', url: '/api/v1/wizard/clearMappings')]
129
-	public function clearMappings(
130
-		string $subject,
131
-	) {
132
-		$mapping = null;
133
-		try {
134
-			if ($subject === 'user') {
135
-				$mapping = Server::get(UserMapping::class);
136
-				$result = $mapping->clearCb(
137
-					function (string $uid): void {
138
-						$this->eventDispatcher->dispatchTyped(new BeforeUserIdUnassignedEvent($uid));
139
-						/** @psalm-suppress UndefinedInterfaceMethod For now we have to emit, will be removed when all hooks are removed */
140
-						Server::get(IUserManager::class)->emit('\OC\User', 'preUnassignedUserId', [$uid]);
141
-					},
142
-					function (string $uid): void {
143
-						$this->eventDispatcher->dispatchTyped(new UserIdUnassignedEvent($uid));
144
-						/** @psalm-suppress UndefinedInterfaceMethod For now we have to emit, will be removed when all hooks are removed */
145
-						Server::get(IUserManager::class)->emit('\OC\User', 'postUnassignedUserId', [$uid]);
146
-					}
147
-				);
148
-			} elseif ($subject === 'group') {
149
-				$mapping = Server::get(GroupMapping::class);
150
-				$result = $mapping->clear();
151
-			} else {
152
-				throw new OCSException($this->l->t('Unsupported subject ' . $subject));
153
-			}
118
+    /**
119
+     * Clear user or group mappings
120
+     *
121
+     * @param 'user'|'group' $subject Whether to clear group or user mappings
122
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
123
+     * @throws OCSException
124
+     *
125
+     * 200: Clearing was done successfuly
126
+     */
127
+    #[AuthorizedAdminSetting(settings: Admin::class)]
128
+    #[ApiRoute(verb: 'POST', url: '/api/v1/wizard/clearMappings')]
129
+    public function clearMappings(
130
+        string $subject,
131
+    ) {
132
+        $mapping = null;
133
+        try {
134
+            if ($subject === 'user') {
135
+                $mapping = Server::get(UserMapping::class);
136
+                $result = $mapping->clearCb(
137
+                    function (string $uid): void {
138
+                        $this->eventDispatcher->dispatchTyped(new BeforeUserIdUnassignedEvent($uid));
139
+                        /** @psalm-suppress UndefinedInterfaceMethod For now we have to emit, will be removed when all hooks are removed */
140
+                        Server::get(IUserManager::class)->emit('\OC\User', 'preUnassignedUserId', [$uid]);
141
+                    },
142
+                    function (string $uid): void {
143
+                        $this->eventDispatcher->dispatchTyped(new UserIdUnassignedEvent($uid));
144
+                        /** @psalm-suppress UndefinedInterfaceMethod For now we have to emit, will be removed when all hooks are removed */
145
+                        Server::get(IUserManager::class)->emit('\OC\User', 'postUnassignedUserId', [$uid]);
146
+                    }
147
+                );
148
+            } elseif ($subject === 'group') {
149
+                $mapping = Server::get(GroupMapping::class);
150
+                $result = $mapping->clear();
151
+            } else {
152
+                throw new OCSException($this->l->t('Unsupported subject ' . $subject));
153
+            }
154 154
 
155
-			if (!$result) {
156
-				throw new OCSException($this->l->t('Failed to clear the mappings.'));
157
-			}
158
-			return new DataResponse();
159
-		} catch (\Exception $e) {
160
-			$this->logger->error($e->getMessage(), ['exception' => $e]);
161
-			throw new OCSException('An issue occurred.');
162
-		}
163
-	}
155
+            if (!$result) {
156
+                throw new OCSException($this->l->t('Failed to clear the mappings.'));
157
+            }
158
+            return new DataResponse();
159
+        } catch (\Exception $e) {
160
+            $this->logger->error($e->getMessage(), ['exception' => $e]);
161
+            throw new OCSException('An issue occurred.');
162
+        }
163
+    }
164 164
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -134,12 +134,12 @@  discard block
 block discarded – undo
134 134
 			if ($subject === 'user') {
135 135
 				$mapping = Server::get(UserMapping::class);
136 136
 				$result = $mapping->clearCb(
137
-					function (string $uid): void {
137
+					function(string $uid): void {
138 138
 						$this->eventDispatcher->dispatchTyped(new BeforeUserIdUnassignedEvent($uid));
139 139
 						/** @psalm-suppress UndefinedInterfaceMethod For now we have to emit, will be removed when all hooks are removed */
140 140
 						Server::get(IUserManager::class)->emit('\OC\User', 'preUnassignedUserId', [$uid]);
141 141
 					},
142
-					function (string $uid): void {
142
+					function(string $uid): void {
143 143
 						$this->eventDispatcher->dispatchTyped(new UserIdUnassignedEvent($uid));
144 144
 						/** @psalm-suppress UndefinedInterfaceMethod For now we have to emit, will be removed when all hooks are removed */
145 145
 						Server::get(IUserManager::class)->emit('\OC\User', 'postUnassignedUserId', [$uid]);
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
 				$mapping = Server::get(GroupMapping::class);
150 150
 				$result = $mapping->clear();
151 151
 			} else {
152
-				throw new OCSException($this->l->t('Unsupported subject ' . $subject));
152
+				throw new OCSException($this->l->t('Unsupported subject '.$subject));
153 153
 			}
154 154
 
155 155
 			if (!$result) {
Please login to merge, or discard this patch.
apps/user_ldap/lib/WizardResult.php 2 patches
Indentation   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -11,51 +11,51 @@
 block discarded – undo
11 11
 namespace OCA\User_LDAP;
12 12
 
13 13
 class WizardResult {
14
-	/**
15
-	 * @var array<string,int|string|int[]|string[]>
16
-	 */
17
-	protected array $changes = [];
18
-	/**
19
-	 * @var array<string,string[]>
20
-	 */
21
-	protected array $options = [];
22
-	protected bool $markedChange = false;
23
-
24
-	/**
25
-	 * @param int|string|int[]|string[] $value
26
-	 */
27
-	public function addChange(string $key, int|string|array $value): void {
28
-		$this->changes[$key] = $value;
29
-	}
30
-
31
-
32
-	public function markChange(): void {
33
-		$this->markedChange = true;
34
-	}
35
-
36
-	/**
37
-	 * @param string|string[] $values
38
-	 */
39
-	public function addOptions(string $key, string|array $values): void {
40
-		if (!is_array($values)) {
41
-			$values = [$values];
42
-		}
43
-		$this->options[$key] = $values;
44
-	}
45
-
46
-	public function hasChanges(): bool {
47
-		return (count($this->changes) > 0 || $this->markedChange);
48
-	}
49
-
50
-	/**
51
-	 * @return array{changes:array<string,int|string|int[]|string[]>,options?:array<string,string[]>}
52
-	 */
53
-	public function getResultArray(): array {
54
-		$result = [];
55
-		$result['changes'] = $this->changes;
56
-		if (count($this->options) > 0) {
57
-			$result['options'] = $this->options;
58
-		}
59
-		return $result;
60
-	}
14
+    /**
15
+     * @var array<string,int|string|int[]|string[]>
16
+     */
17
+    protected array $changes = [];
18
+    /**
19
+     * @var array<string,string[]>
20
+     */
21
+    protected array $options = [];
22
+    protected bool $markedChange = false;
23
+
24
+    /**
25
+     * @param int|string|int[]|string[] $value
26
+     */
27
+    public function addChange(string $key, int|string|array $value): void {
28
+        $this->changes[$key] = $value;
29
+    }
30
+
31
+
32
+    public function markChange(): void {
33
+        $this->markedChange = true;
34
+    }
35
+
36
+    /**
37
+     * @param string|string[] $values
38
+     */
39
+    public function addOptions(string $key, string|array $values): void {
40
+        if (!is_array($values)) {
41
+            $values = [$values];
42
+        }
43
+        $this->options[$key] = $values;
44
+    }
45
+
46
+    public function hasChanges(): bool {
47
+        return (count($this->changes) > 0 || $this->markedChange);
48
+    }
49
+
50
+    /**
51
+     * @return array{changes:array<string,int|string|int[]|string[]>,options?:array<string,string[]>}
52
+     */
53
+    public function getResultArray(): array {
54
+        $result = [];
55
+        $result['changes'] = $this->changes;
56
+        if (count($this->options) > 0) {
57
+            $result['options'] = $this->options;
58
+        }
59
+        return $result;
60
+    }
61 61
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
 	/**
25 25
 	 * @param int|string|int[]|string[] $value
26 26
 	 */
27
-	public function addChange(string $key, int|string|array $value): void {
27
+	public function addChange(string $key, int | string | array $value): void {
28 28
 		$this->changes[$key] = $value;
29 29
 	}
30 30
 
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
 	/**
37 37
 	 * @param string|string[] $values
38 38
 	 */
39
-	public function addOptions(string $key, string|array $values): void {
39
+	public function addOptions(string $key, string | array $values): void {
40 40
 		if (!is_array($values)) {
41 41
 			$values = [$values];
42 42
 		}
Please login to merge, or discard this patch.
apps/user_ldap/lib/WizardFactory.php 2 patches
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -10,22 +10,22 @@
 block discarded – undo
10 10
 namespace OCA\User_LDAP;
11 11
 
12 12
 class WizardFactory {
13
-	public function __construct(
14
-		private ILDAPWrapper $ldap,
15
-		private AccessFactory $accessFactory,
16
-	) {
17
-	}
13
+    public function __construct(
14
+        private ILDAPWrapper $ldap,
15
+        private AccessFactory $accessFactory,
16
+    ) {
17
+    }
18 18
 
19
-	public function get(string $configID): Wizard {
20
-		$configuration = new Configuration($configID);
19
+    public function get(string $configID): Wizard {
20
+        $configuration = new Configuration($configID);
21 21
 
22
-		$connection = new Connection($this->ldap, $configID, null);
23
-		$connection->setConfiguration($configuration->getConfiguration());
24
-		$connection->ldapConfigurationActive = (string)true;
25
-		$connection->setIgnoreValidation(true);
22
+        $connection = new Connection($this->ldap, $configID, null);
23
+        $connection->setConfiguration($configuration->getConfiguration());
24
+        $connection->ldapConfigurationActive = (string)true;
25
+        $connection->setIgnoreValidation(true);
26 26
 
27
-		$access = $this->accessFactory->get($connection);
27
+        $access = $this->accessFactory->get($connection);
28 28
 
29
-		return new Wizard($configuration, $this->ldap, $access);
30
-	}
29
+        return new Wizard($configuration, $this->ldap, $access);
30
+    }
31 31
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -21,7 +21,7 @@
 block discarded – undo
21 21
 
22 22
 		$connection = new Connection($this->ldap, $configID, null);
23 23
 		$connection->setConfiguration($configuration->getConfiguration());
24
-		$connection->ldapConfigurationActive = (string)true;
24
+		$connection->ldapConfigurationActive = (string) true;
25 25
 		$connection->setIgnoreValidation(true);
26 26
 
27 27
 		$access = $this->accessFactory->get($connection);
Please login to merge, or discard this patch.
apps/user_ldap/appinfo/routes.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -9,10 +9,10 @@
 block discarded – undo
9 9
  */
10 10
 
11 11
 return [
12
-	'routes' => [
13
-		['name' => 'renewPassword#tryRenewPassword', 'url' => '/renewpassword', 'verb' => 'POST'],
14
-		['name' => 'renewPassword#showRenewPasswordForm', 'url' => '/renewpassword/{user}', 'verb' => 'GET'],
15
-		['name' => 'renewPassword#cancel', 'url' => '/renewpassword/cancel', 'verb' => 'GET'],
16
-		['name' => 'renewPassword#showLoginFormInvalidPassword', 'url' => '/renewpassword/invalidlogin/{user}', 'verb' => 'GET'],
17
-	],
12
+    'routes' => [
13
+        ['name' => 'renewPassword#tryRenewPassword', 'url' => '/renewpassword', 'verb' => 'POST'],
14
+        ['name' => 'renewPassword#showRenewPasswordForm', 'url' => '/renewpassword/{user}', 'verb' => 'GET'],
15
+        ['name' => 'renewPassword#cancel', 'url' => '/renewpassword/cancel', 'verb' => 'GET'],
16
+        ['name' => 'renewPassword#showLoginFormInvalidPassword', 'url' => '/renewpassword/invalidlogin/{user}', 'verb' => 'GET'],
17
+    ],
18 18
 ];
Please login to merge, or discard this patch.
apps/user_ldap/composer/composer/autoload_static.php 1 patch
Spacing   +99 added lines, -99 removed lines patch added patch discarded remove patch
@@ -6,118 +6,118 @@
 block discarded – undo
6 6
 
7 7
 class ComposerStaticInitUser_LDAP
8 8
 {
9
-    public static $prefixLengthsPsr4 = array (
9
+    public static $prefixLengthsPsr4 = array(
10 10
         'O' => 
11
-        array (
11
+        array(
12 12
             'OCA\\User_LDAP\\' => 14,
13 13
         ),
14 14
     );
15 15
 
16
-    public static $prefixDirsPsr4 = array (
16
+    public static $prefixDirsPsr4 = array(
17 17
         'OCA\\User_LDAP\\' => 
18
-        array (
19
-            0 => __DIR__ . '/..' . '/../lib',
18
+        array(
19
+            0 => __DIR__.'/..'.'/../lib',
20 20
         ),
21 21
     );
22 22
 
23
-    public static $classMap = array (
24
-        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
25
-        'OCA\\User_LDAP\\Access' => __DIR__ . '/..' . '/../lib/Access.php',
26
-        'OCA\\User_LDAP\\AccessFactory' => __DIR__ . '/..' . '/../lib/AccessFactory.php',
27
-        'OCA\\User_LDAP\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
28
-        'OCA\\User_LDAP\\BackendUtility' => __DIR__ . '/..' . '/../lib/BackendUtility.php',
29
-        'OCA\\User_LDAP\\Command\\CheckGroup' => __DIR__ . '/..' . '/../lib/Command/CheckGroup.php',
30
-        'OCA\\User_LDAP\\Command\\CheckUser' => __DIR__ . '/..' . '/../lib/Command/CheckUser.php',
31
-        'OCA\\User_LDAP\\Command\\CreateEmptyConfig' => __DIR__ . '/..' . '/../lib/Command/CreateEmptyConfig.php',
32
-        'OCA\\User_LDAP\\Command\\DeleteConfig' => __DIR__ . '/..' . '/../lib/Command/DeleteConfig.php',
33
-        'OCA\\User_LDAP\\Command\\PromoteGroup' => __DIR__ . '/..' . '/../lib/Command/PromoteGroup.php',
34
-        'OCA\\User_LDAP\\Command\\ResetGroup' => __DIR__ . '/..' . '/../lib/Command/ResetGroup.php',
35
-        'OCA\\User_LDAP\\Command\\ResetUser' => __DIR__ . '/..' . '/../lib/Command/ResetUser.php',
36
-        'OCA\\User_LDAP\\Command\\Search' => __DIR__ . '/..' . '/../lib/Command/Search.php',
37
-        'OCA\\User_LDAP\\Command\\SetConfig' => __DIR__ . '/..' . '/../lib/Command/SetConfig.php',
38
-        'OCA\\User_LDAP\\Command\\ShowConfig' => __DIR__ . '/..' . '/../lib/Command/ShowConfig.php',
39
-        'OCA\\User_LDAP\\Command\\ShowRemnants' => __DIR__ . '/..' . '/../lib/Command/ShowRemnants.php',
40
-        'OCA\\User_LDAP\\Command\\TestConfig' => __DIR__ . '/..' . '/../lib/Command/TestConfig.php',
41
-        'OCA\\User_LDAP\\Command\\TestUserSettings' => __DIR__ . '/..' . '/../lib/Command/TestUserSettings.php',
42
-        'OCA\\User_LDAP\\Command\\UpdateUUID' => __DIR__ . '/..' . '/../lib/Command/UpdateUUID.php',
43
-        'OCA\\User_LDAP\\Configuration' => __DIR__ . '/..' . '/../lib/Configuration.php',
44
-        'OCA\\User_LDAP\\Connection' => __DIR__ . '/..' . '/../lib/Connection.php',
45
-        'OCA\\User_LDAP\\ConnectionFactory' => __DIR__ . '/..' . '/../lib/ConnectionFactory.php',
46
-        'OCA\\User_LDAP\\Controller\\ConfigAPIController' => __DIR__ . '/..' . '/../lib/Controller/ConfigAPIController.php',
47
-        'OCA\\User_LDAP\\Controller\\RenewPasswordController' => __DIR__ . '/..' . '/../lib/Controller/RenewPasswordController.php',
48
-        'OCA\\User_LDAP\\Controller\\WizardController' => __DIR__ . '/..' . '/../lib/Controller/WizardController.php',
49
-        'OCA\\User_LDAP\\DataCollector\\LdapDataCollector' => __DIR__ . '/..' . '/../lib/DataCollector/LdapDataCollector.php',
50
-        'OCA\\User_LDAP\\Db\\GroupMembership' => __DIR__ . '/..' . '/../lib/Db/GroupMembership.php',
51
-        'OCA\\User_LDAP\\Db\\GroupMembershipMapper' => __DIR__ . '/..' . '/../lib/Db/GroupMembershipMapper.php',
52
-        'OCA\\User_LDAP\\Events\\GroupBackendRegistered' => __DIR__ . '/..' . '/../lib/Events/GroupBackendRegistered.php',
53
-        'OCA\\User_LDAP\\Events\\UserBackendRegistered' => __DIR__ . '/..' . '/../lib/Events/UserBackendRegistered.php',
54
-        'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => __DIR__ . '/..' . '/../lib/Exceptions/AttributeNotSet.php',
55
-        'OCA\\User_LDAP\\Exceptions\\ConfigurationIssueException' => __DIR__ . '/..' . '/../lib/Exceptions/ConfigurationIssueException.php',
56
-        'OCA\\User_LDAP\\Exceptions\\ConstraintViolationException' => __DIR__ . '/..' . '/../lib/Exceptions/ConstraintViolationException.php',
57
-        'OCA\\User_LDAP\\Exceptions\\NoMoreResults' => __DIR__ . '/..' . '/../lib/Exceptions/NoMoreResults.php',
58
-        'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => __DIR__ . '/..' . '/../lib/Exceptions/NotOnLDAP.php',
59
-        'OCA\\User_LDAP\\GroupPluginManager' => __DIR__ . '/..' . '/../lib/GroupPluginManager.php',
60
-        'OCA\\User_LDAP\\Group_LDAP' => __DIR__ . '/..' . '/../lib/Group_LDAP.php',
61
-        'OCA\\User_LDAP\\Group_Proxy' => __DIR__ . '/..' . '/../lib/Group_Proxy.php',
62
-        'OCA\\User_LDAP\\Handler\\ExtStorageConfigHandler' => __DIR__ . '/..' . '/../lib/Handler/ExtStorageConfigHandler.php',
63
-        'OCA\\User_LDAP\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
64
-        'OCA\\User_LDAP\\IGroupLDAP' => __DIR__ . '/..' . '/../lib/IGroupLDAP.php',
65
-        'OCA\\User_LDAP\\ILDAPGroupPlugin' => __DIR__ . '/..' . '/../lib/ILDAPGroupPlugin.php',
66
-        'OCA\\User_LDAP\\ILDAPUserPlugin' => __DIR__ . '/..' . '/../lib/ILDAPUserPlugin.php',
67
-        'OCA\\User_LDAP\\ILDAPWrapper' => __DIR__ . '/..' . '/../lib/ILDAPWrapper.php',
68
-        'OCA\\User_LDAP\\IUserLDAP' => __DIR__ . '/..' . '/../lib/IUserLDAP.php',
69
-        'OCA\\User_LDAP\\Jobs\\CleanUp' => __DIR__ . '/..' . '/../lib/Jobs/CleanUp.php',
70
-        'OCA\\User_LDAP\\Jobs\\Sync' => __DIR__ . '/..' . '/../lib/Jobs/Sync.php',
71
-        'OCA\\User_LDAP\\Jobs\\UpdateGroups' => __DIR__ . '/..' . '/../lib/Jobs/UpdateGroups.php',
72
-        'OCA\\User_LDAP\\LDAP' => __DIR__ . '/..' . '/../lib/LDAP.php',
73
-        'OCA\\User_LDAP\\LDAPProvider' => __DIR__ . '/..' . '/../lib/LDAPProvider.php',
74
-        'OCA\\User_LDAP\\LDAPProviderFactory' => __DIR__ . '/..' . '/../lib/LDAPProviderFactory.php',
75
-        'OCA\\User_LDAP\\LDAPUtility' => __DIR__ . '/..' . '/../lib/LDAPUtility.php',
76
-        'OCA\\User_LDAP\\LoginListener' => __DIR__ . '/..' . '/../lib/LoginListener.php',
77
-        'OCA\\User_LDAP\\Mapping\\AbstractMapping' => __DIR__ . '/..' . '/../lib/Mapping/AbstractMapping.php',
78
-        'OCA\\User_LDAP\\Mapping\\GroupMapping' => __DIR__ . '/..' . '/../lib/Mapping/GroupMapping.php',
79
-        'OCA\\User_LDAP\\Mapping\\UserMapping' => __DIR__ . '/..' . '/../lib/Mapping/UserMapping.php',
80
-        'OCA\\User_LDAP\\Migration\\GroupMappingMigration' => __DIR__ . '/..' . '/../lib/Migration/GroupMappingMigration.php',
81
-        'OCA\\User_LDAP\\Migration\\RemoveRefreshTime' => __DIR__ . '/..' . '/../lib/Migration/RemoveRefreshTime.php',
82
-        'OCA\\User_LDAP\\Migration\\SetDefaultProvider' => __DIR__ . '/..' . '/../lib/Migration/SetDefaultProvider.php',
83
-        'OCA\\User_LDAP\\Migration\\UUIDFix' => __DIR__ . '/..' . '/../lib/Migration/UUIDFix.php',
84
-        'OCA\\User_LDAP\\Migration\\UUIDFixGroup' => __DIR__ . '/..' . '/../lib/Migration/UUIDFixGroup.php',
85
-        'OCA\\User_LDAP\\Migration\\UUIDFixInsert' => __DIR__ . '/..' . '/../lib/Migration/UUIDFixInsert.php',
86
-        'OCA\\User_LDAP\\Migration\\UUIDFixUser' => __DIR__ . '/..' . '/../lib/Migration/UUIDFixUser.php',
87
-        'OCA\\User_LDAP\\Migration\\UnsetDefaultProvider' => __DIR__ . '/..' . '/../lib/Migration/UnsetDefaultProvider.php',
88
-        'OCA\\User_LDAP\\Migration\\Version1010Date20200630192842' => __DIR__ . '/..' . '/../lib/Migration/Version1010Date20200630192842.php',
89
-        'OCA\\User_LDAP\\Migration\\Version1120Date20210917155206' => __DIR__ . '/..' . '/../lib/Migration/Version1120Date20210917155206.php',
90
-        'OCA\\User_LDAP\\Migration\\Version1130Date20211102154716' => __DIR__ . '/..' . '/../lib/Migration/Version1130Date20211102154716.php',
91
-        'OCA\\User_LDAP\\Migration\\Version1130Date20220110154717' => __DIR__ . '/..' . '/../lib/Migration/Version1130Date20220110154717.php',
92
-        'OCA\\User_LDAP\\Migration\\Version1130Date20220110154718' => __DIR__ . '/..' . '/../lib/Migration/Version1130Date20220110154718.php',
93
-        'OCA\\User_LDAP\\Migration\\Version1130Date20220110154719' => __DIR__ . '/..' . '/../lib/Migration/Version1130Date20220110154719.php',
94
-        'OCA\\User_LDAP\\Migration\\Version1141Date20220323143801' => __DIR__ . '/..' . '/../lib/Migration/Version1141Date20220323143801.php',
95
-        'OCA\\User_LDAP\\Migration\\Version1190Date20230706134108' => __DIR__ . '/..' . '/../lib/Migration/Version1190Date20230706134108.php',
96
-        'OCA\\User_LDAP\\Migration\\Version1190Date20230706134109' => __DIR__ . '/..' . '/../lib/Migration/Version1190Date20230706134109.php',
97
-        'OCA\\User_LDAP\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
98
-        'OCA\\User_LDAP\\PagedResults\\TLinkId' => __DIR__ . '/..' . '/../lib/PagedResults/TLinkId.php',
99
-        'OCA\\User_LDAP\\Proxy' => __DIR__ . '/..' . '/../lib/Proxy.php',
100
-        'OCA\\User_LDAP\\Service\\BirthdateParserService' => __DIR__ . '/..' . '/../lib/Service/BirthdateParserService.php',
101
-        'OCA\\User_LDAP\\Service\\UpdateGroupsService' => __DIR__ . '/..' . '/../lib/Service/UpdateGroupsService.php',
102
-        'OCA\\User_LDAP\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
103
-        'OCA\\User_LDAP\\Settings\\Section' => __DIR__ . '/..' . '/../lib/Settings/Section.php',
104
-        'OCA\\User_LDAP\\SetupChecks\\LdapConnection' => __DIR__ . '/..' . '/../lib/SetupChecks/LdapConnection.php',
105
-        'OCA\\User_LDAP\\SetupChecks\\LdapInvalidUuids' => __DIR__ . '/..' . '/../lib/SetupChecks/LdapInvalidUuids.php',
106
-        'OCA\\User_LDAP\\UserPluginManager' => __DIR__ . '/..' . '/../lib/UserPluginManager.php',
107
-        'OCA\\User_LDAP\\User\\DeletedUsersIndex' => __DIR__ . '/..' . '/../lib/User/DeletedUsersIndex.php',
108
-        'OCA\\User_LDAP\\User\\Manager' => __DIR__ . '/..' . '/../lib/User/Manager.php',
109
-        'OCA\\User_LDAP\\User\\OfflineUser' => __DIR__ . '/..' . '/../lib/User/OfflineUser.php',
110
-        'OCA\\User_LDAP\\User\\User' => __DIR__ . '/..' . '/../lib/User/User.php',
111
-        'OCA\\User_LDAP\\User_LDAP' => __DIR__ . '/..' . '/../lib/User_LDAP.php',
112
-        'OCA\\User_LDAP\\User_Proxy' => __DIR__ . '/..' . '/../lib/User_Proxy.php',
113
-        'OCA\\User_LDAP\\Wizard' => __DIR__ . '/..' . '/../lib/Wizard.php',
114
-        'OCA\\User_LDAP\\WizardFactory' => __DIR__ . '/..' . '/../lib/WizardFactory.php',
115
-        'OCA\\User_LDAP\\WizardResult' => __DIR__ . '/..' . '/../lib/WizardResult.php',
23
+    public static $classMap = array(
24
+        'Composer\\InstalledVersions' => __DIR__.'/..'.'/composer/InstalledVersions.php',
25
+        'OCA\\User_LDAP\\Access' => __DIR__.'/..'.'/../lib/Access.php',
26
+        'OCA\\User_LDAP\\AccessFactory' => __DIR__.'/..'.'/../lib/AccessFactory.php',
27
+        'OCA\\User_LDAP\\AppInfo\\Application' => __DIR__.'/..'.'/../lib/AppInfo/Application.php',
28
+        'OCA\\User_LDAP\\BackendUtility' => __DIR__.'/..'.'/../lib/BackendUtility.php',
29
+        'OCA\\User_LDAP\\Command\\CheckGroup' => __DIR__.'/..'.'/../lib/Command/CheckGroup.php',
30
+        'OCA\\User_LDAP\\Command\\CheckUser' => __DIR__.'/..'.'/../lib/Command/CheckUser.php',
31
+        'OCA\\User_LDAP\\Command\\CreateEmptyConfig' => __DIR__.'/..'.'/../lib/Command/CreateEmptyConfig.php',
32
+        'OCA\\User_LDAP\\Command\\DeleteConfig' => __DIR__.'/..'.'/../lib/Command/DeleteConfig.php',
33
+        'OCA\\User_LDAP\\Command\\PromoteGroup' => __DIR__.'/..'.'/../lib/Command/PromoteGroup.php',
34
+        'OCA\\User_LDAP\\Command\\ResetGroup' => __DIR__.'/..'.'/../lib/Command/ResetGroup.php',
35
+        'OCA\\User_LDAP\\Command\\ResetUser' => __DIR__.'/..'.'/../lib/Command/ResetUser.php',
36
+        'OCA\\User_LDAP\\Command\\Search' => __DIR__.'/..'.'/../lib/Command/Search.php',
37
+        'OCA\\User_LDAP\\Command\\SetConfig' => __DIR__.'/..'.'/../lib/Command/SetConfig.php',
38
+        'OCA\\User_LDAP\\Command\\ShowConfig' => __DIR__.'/..'.'/../lib/Command/ShowConfig.php',
39
+        'OCA\\User_LDAP\\Command\\ShowRemnants' => __DIR__.'/..'.'/../lib/Command/ShowRemnants.php',
40
+        'OCA\\User_LDAP\\Command\\TestConfig' => __DIR__.'/..'.'/../lib/Command/TestConfig.php',
41
+        'OCA\\User_LDAP\\Command\\TestUserSettings' => __DIR__.'/..'.'/../lib/Command/TestUserSettings.php',
42
+        'OCA\\User_LDAP\\Command\\UpdateUUID' => __DIR__.'/..'.'/../lib/Command/UpdateUUID.php',
43
+        'OCA\\User_LDAP\\Configuration' => __DIR__.'/..'.'/../lib/Configuration.php',
44
+        'OCA\\User_LDAP\\Connection' => __DIR__.'/..'.'/../lib/Connection.php',
45
+        'OCA\\User_LDAP\\ConnectionFactory' => __DIR__.'/..'.'/../lib/ConnectionFactory.php',
46
+        'OCA\\User_LDAP\\Controller\\ConfigAPIController' => __DIR__.'/..'.'/../lib/Controller/ConfigAPIController.php',
47
+        'OCA\\User_LDAP\\Controller\\RenewPasswordController' => __DIR__.'/..'.'/../lib/Controller/RenewPasswordController.php',
48
+        'OCA\\User_LDAP\\Controller\\WizardController' => __DIR__.'/..'.'/../lib/Controller/WizardController.php',
49
+        'OCA\\User_LDAP\\DataCollector\\LdapDataCollector' => __DIR__.'/..'.'/../lib/DataCollector/LdapDataCollector.php',
50
+        'OCA\\User_LDAP\\Db\\GroupMembership' => __DIR__.'/..'.'/../lib/Db/GroupMembership.php',
51
+        'OCA\\User_LDAP\\Db\\GroupMembershipMapper' => __DIR__.'/..'.'/../lib/Db/GroupMembershipMapper.php',
52
+        'OCA\\User_LDAP\\Events\\GroupBackendRegistered' => __DIR__.'/..'.'/../lib/Events/GroupBackendRegistered.php',
53
+        'OCA\\User_LDAP\\Events\\UserBackendRegistered' => __DIR__.'/..'.'/../lib/Events/UserBackendRegistered.php',
54
+        'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => __DIR__.'/..'.'/../lib/Exceptions/AttributeNotSet.php',
55
+        'OCA\\User_LDAP\\Exceptions\\ConfigurationIssueException' => __DIR__.'/..'.'/../lib/Exceptions/ConfigurationIssueException.php',
56
+        'OCA\\User_LDAP\\Exceptions\\ConstraintViolationException' => __DIR__.'/..'.'/../lib/Exceptions/ConstraintViolationException.php',
57
+        'OCA\\User_LDAP\\Exceptions\\NoMoreResults' => __DIR__.'/..'.'/../lib/Exceptions/NoMoreResults.php',
58
+        'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => __DIR__.'/..'.'/../lib/Exceptions/NotOnLDAP.php',
59
+        'OCA\\User_LDAP\\GroupPluginManager' => __DIR__.'/..'.'/../lib/GroupPluginManager.php',
60
+        'OCA\\User_LDAP\\Group_LDAP' => __DIR__.'/..'.'/../lib/Group_LDAP.php',
61
+        'OCA\\User_LDAP\\Group_Proxy' => __DIR__.'/..'.'/../lib/Group_Proxy.php',
62
+        'OCA\\User_LDAP\\Handler\\ExtStorageConfigHandler' => __DIR__.'/..'.'/../lib/Handler/ExtStorageConfigHandler.php',
63
+        'OCA\\User_LDAP\\Helper' => __DIR__.'/..'.'/../lib/Helper.php',
64
+        'OCA\\User_LDAP\\IGroupLDAP' => __DIR__.'/..'.'/../lib/IGroupLDAP.php',
65
+        'OCA\\User_LDAP\\ILDAPGroupPlugin' => __DIR__.'/..'.'/../lib/ILDAPGroupPlugin.php',
66
+        'OCA\\User_LDAP\\ILDAPUserPlugin' => __DIR__.'/..'.'/../lib/ILDAPUserPlugin.php',
67
+        'OCA\\User_LDAP\\ILDAPWrapper' => __DIR__.'/..'.'/../lib/ILDAPWrapper.php',
68
+        'OCA\\User_LDAP\\IUserLDAP' => __DIR__.'/..'.'/../lib/IUserLDAP.php',
69
+        'OCA\\User_LDAP\\Jobs\\CleanUp' => __DIR__.'/..'.'/../lib/Jobs/CleanUp.php',
70
+        'OCA\\User_LDAP\\Jobs\\Sync' => __DIR__.'/..'.'/../lib/Jobs/Sync.php',
71
+        'OCA\\User_LDAP\\Jobs\\UpdateGroups' => __DIR__.'/..'.'/../lib/Jobs/UpdateGroups.php',
72
+        'OCA\\User_LDAP\\LDAP' => __DIR__.'/..'.'/../lib/LDAP.php',
73
+        'OCA\\User_LDAP\\LDAPProvider' => __DIR__.'/..'.'/../lib/LDAPProvider.php',
74
+        'OCA\\User_LDAP\\LDAPProviderFactory' => __DIR__.'/..'.'/../lib/LDAPProviderFactory.php',
75
+        'OCA\\User_LDAP\\LDAPUtility' => __DIR__.'/..'.'/../lib/LDAPUtility.php',
76
+        'OCA\\User_LDAP\\LoginListener' => __DIR__.'/..'.'/../lib/LoginListener.php',
77
+        'OCA\\User_LDAP\\Mapping\\AbstractMapping' => __DIR__.'/..'.'/../lib/Mapping/AbstractMapping.php',
78
+        'OCA\\User_LDAP\\Mapping\\GroupMapping' => __DIR__.'/..'.'/../lib/Mapping/GroupMapping.php',
79
+        'OCA\\User_LDAP\\Mapping\\UserMapping' => __DIR__.'/..'.'/../lib/Mapping/UserMapping.php',
80
+        'OCA\\User_LDAP\\Migration\\GroupMappingMigration' => __DIR__.'/..'.'/../lib/Migration/GroupMappingMigration.php',
81
+        'OCA\\User_LDAP\\Migration\\RemoveRefreshTime' => __DIR__.'/..'.'/../lib/Migration/RemoveRefreshTime.php',
82
+        'OCA\\User_LDAP\\Migration\\SetDefaultProvider' => __DIR__.'/..'.'/../lib/Migration/SetDefaultProvider.php',
83
+        'OCA\\User_LDAP\\Migration\\UUIDFix' => __DIR__.'/..'.'/../lib/Migration/UUIDFix.php',
84
+        'OCA\\User_LDAP\\Migration\\UUIDFixGroup' => __DIR__.'/..'.'/../lib/Migration/UUIDFixGroup.php',
85
+        'OCA\\User_LDAP\\Migration\\UUIDFixInsert' => __DIR__.'/..'.'/../lib/Migration/UUIDFixInsert.php',
86
+        'OCA\\User_LDAP\\Migration\\UUIDFixUser' => __DIR__.'/..'.'/../lib/Migration/UUIDFixUser.php',
87
+        'OCA\\User_LDAP\\Migration\\UnsetDefaultProvider' => __DIR__.'/..'.'/../lib/Migration/UnsetDefaultProvider.php',
88
+        'OCA\\User_LDAP\\Migration\\Version1010Date20200630192842' => __DIR__.'/..'.'/../lib/Migration/Version1010Date20200630192842.php',
89
+        'OCA\\User_LDAP\\Migration\\Version1120Date20210917155206' => __DIR__.'/..'.'/../lib/Migration/Version1120Date20210917155206.php',
90
+        'OCA\\User_LDAP\\Migration\\Version1130Date20211102154716' => __DIR__.'/..'.'/../lib/Migration/Version1130Date20211102154716.php',
91
+        'OCA\\User_LDAP\\Migration\\Version1130Date20220110154717' => __DIR__.'/..'.'/../lib/Migration/Version1130Date20220110154717.php',
92
+        'OCA\\User_LDAP\\Migration\\Version1130Date20220110154718' => __DIR__.'/..'.'/../lib/Migration/Version1130Date20220110154718.php',
93
+        'OCA\\User_LDAP\\Migration\\Version1130Date20220110154719' => __DIR__.'/..'.'/../lib/Migration/Version1130Date20220110154719.php',
94
+        'OCA\\User_LDAP\\Migration\\Version1141Date20220323143801' => __DIR__.'/..'.'/../lib/Migration/Version1141Date20220323143801.php',
95
+        'OCA\\User_LDAP\\Migration\\Version1190Date20230706134108' => __DIR__.'/..'.'/../lib/Migration/Version1190Date20230706134108.php',
96
+        'OCA\\User_LDAP\\Migration\\Version1190Date20230706134109' => __DIR__.'/..'.'/../lib/Migration/Version1190Date20230706134109.php',
97
+        'OCA\\User_LDAP\\Notification\\Notifier' => __DIR__.'/..'.'/../lib/Notification/Notifier.php',
98
+        'OCA\\User_LDAP\\PagedResults\\TLinkId' => __DIR__.'/..'.'/../lib/PagedResults/TLinkId.php',
99
+        'OCA\\User_LDAP\\Proxy' => __DIR__.'/..'.'/../lib/Proxy.php',
100
+        'OCA\\User_LDAP\\Service\\BirthdateParserService' => __DIR__.'/..'.'/../lib/Service/BirthdateParserService.php',
101
+        'OCA\\User_LDAP\\Service\\UpdateGroupsService' => __DIR__.'/..'.'/../lib/Service/UpdateGroupsService.php',
102
+        'OCA\\User_LDAP\\Settings\\Admin' => __DIR__.'/..'.'/../lib/Settings/Admin.php',
103
+        'OCA\\User_LDAP\\Settings\\Section' => __DIR__.'/..'.'/../lib/Settings/Section.php',
104
+        'OCA\\User_LDAP\\SetupChecks\\LdapConnection' => __DIR__.'/..'.'/../lib/SetupChecks/LdapConnection.php',
105
+        'OCA\\User_LDAP\\SetupChecks\\LdapInvalidUuids' => __DIR__.'/..'.'/../lib/SetupChecks/LdapInvalidUuids.php',
106
+        'OCA\\User_LDAP\\UserPluginManager' => __DIR__.'/..'.'/../lib/UserPluginManager.php',
107
+        'OCA\\User_LDAP\\User\\DeletedUsersIndex' => __DIR__.'/..'.'/../lib/User/DeletedUsersIndex.php',
108
+        'OCA\\User_LDAP\\User\\Manager' => __DIR__.'/..'.'/../lib/User/Manager.php',
109
+        'OCA\\User_LDAP\\User\\OfflineUser' => __DIR__.'/..'.'/../lib/User/OfflineUser.php',
110
+        'OCA\\User_LDAP\\User\\User' => __DIR__.'/..'.'/../lib/User/User.php',
111
+        'OCA\\User_LDAP\\User_LDAP' => __DIR__.'/..'.'/../lib/User_LDAP.php',
112
+        'OCA\\User_LDAP\\User_Proxy' => __DIR__.'/..'.'/../lib/User_Proxy.php',
113
+        'OCA\\User_LDAP\\Wizard' => __DIR__.'/..'.'/../lib/Wizard.php',
114
+        'OCA\\User_LDAP\\WizardFactory' => __DIR__.'/..'.'/../lib/WizardFactory.php',
115
+        'OCA\\User_LDAP\\WizardResult' => __DIR__.'/..'.'/../lib/WizardResult.php',
116 116
     );
117 117
 
118 118
     public static function getInitializer(ClassLoader $loader)
119 119
     {
120
-        return \Closure::bind(function () use ($loader) {
120
+        return \Closure::bind(function() use ($loader) {
121 121
             $loader->prefixLengthsPsr4 = ComposerStaticInitUser_LDAP::$prefixLengthsPsr4;
122 122
             $loader->prefixDirsPsr4 = ComposerStaticInitUser_LDAP::$prefixDirsPsr4;
123 123
             $loader->classMap = ComposerStaticInitUser_LDAP::$classMap;
Please login to merge, or discard this patch.
apps/user_ldap/composer/composer/autoload_classmap.php 1 patch
Spacing   +92 added lines, -92 removed lines patch added patch discarded remove patch
@@ -6,96 +6,96 @@
 block discarded – undo
6 6
 $baseDir = $vendorDir;
7 7
 
8 8
 return array(
9
-    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
10
-    'OCA\\User_LDAP\\Access' => $baseDir . '/../lib/Access.php',
11
-    'OCA\\User_LDAP\\AccessFactory' => $baseDir . '/../lib/AccessFactory.php',
12
-    'OCA\\User_LDAP\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
13
-    'OCA\\User_LDAP\\BackendUtility' => $baseDir . '/../lib/BackendUtility.php',
14
-    'OCA\\User_LDAP\\Command\\CheckGroup' => $baseDir . '/../lib/Command/CheckGroup.php',
15
-    'OCA\\User_LDAP\\Command\\CheckUser' => $baseDir . '/../lib/Command/CheckUser.php',
16
-    'OCA\\User_LDAP\\Command\\CreateEmptyConfig' => $baseDir . '/../lib/Command/CreateEmptyConfig.php',
17
-    'OCA\\User_LDAP\\Command\\DeleteConfig' => $baseDir . '/../lib/Command/DeleteConfig.php',
18
-    'OCA\\User_LDAP\\Command\\PromoteGroup' => $baseDir . '/../lib/Command/PromoteGroup.php',
19
-    'OCA\\User_LDAP\\Command\\ResetGroup' => $baseDir . '/../lib/Command/ResetGroup.php',
20
-    'OCA\\User_LDAP\\Command\\ResetUser' => $baseDir . '/../lib/Command/ResetUser.php',
21
-    'OCA\\User_LDAP\\Command\\Search' => $baseDir . '/../lib/Command/Search.php',
22
-    'OCA\\User_LDAP\\Command\\SetConfig' => $baseDir . '/../lib/Command/SetConfig.php',
23
-    'OCA\\User_LDAP\\Command\\ShowConfig' => $baseDir . '/../lib/Command/ShowConfig.php',
24
-    'OCA\\User_LDAP\\Command\\ShowRemnants' => $baseDir . '/../lib/Command/ShowRemnants.php',
25
-    'OCA\\User_LDAP\\Command\\TestConfig' => $baseDir . '/../lib/Command/TestConfig.php',
26
-    'OCA\\User_LDAP\\Command\\TestUserSettings' => $baseDir . '/../lib/Command/TestUserSettings.php',
27
-    'OCA\\User_LDAP\\Command\\UpdateUUID' => $baseDir . '/../lib/Command/UpdateUUID.php',
28
-    'OCA\\User_LDAP\\Configuration' => $baseDir . '/../lib/Configuration.php',
29
-    'OCA\\User_LDAP\\Connection' => $baseDir . '/../lib/Connection.php',
30
-    'OCA\\User_LDAP\\ConnectionFactory' => $baseDir . '/../lib/ConnectionFactory.php',
31
-    'OCA\\User_LDAP\\Controller\\ConfigAPIController' => $baseDir . '/../lib/Controller/ConfigAPIController.php',
32
-    'OCA\\User_LDAP\\Controller\\RenewPasswordController' => $baseDir . '/../lib/Controller/RenewPasswordController.php',
33
-    'OCA\\User_LDAP\\Controller\\WizardController' => $baseDir . '/../lib/Controller/WizardController.php',
34
-    'OCA\\User_LDAP\\DataCollector\\LdapDataCollector' => $baseDir . '/../lib/DataCollector/LdapDataCollector.php',
35
-    'OCA\\User_LDAP\\Db\\GroupMembership' => $baseDir . '/../lib/Db/GroupMembership.php',
36
-    'OCA\\User_LDAP\\Db\\GroupMembershipMapper' => $baseDir . '/../lib/Db/GroupMembershipMapper.php',
37
-    'OCA\\User_LDAP\\Events\\GroupBackendRegistered' => $baseDir . '/../lib/Events/GroupBackendRegistered.php',
38
-    'OCA\\User_LDAP\\Events\\UserBackendRegistered' => $baseDir . '/../lib/Events/UserBackendRegistered.php',
39
-    'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => $baseDir . '/../lib/Exceptions/AttributeNotSet.php',
40
-    'OCA\\User_LDAP\\Exceptions\\ConfigurationIssueException' => $baseDir . '/../lib/Exceptions/ConfigurationIssueException.php',
41
-    'OCA\\User_LDAP\\Exceptions\\ConstraintViolationException' => $baseDir . '/../lib/Exceptions/ConstraintViolationException.php',
42
-    'OCA\\User_LDAP\\Exceptions\\NoMoreResults' => $baseDir . '/../lib/Exceptions/NoMoreResults.php',
43
-    'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => $baseDir . '/../lib/Exceptions/NotOnLDAP.php',
44
-    'OCA\\User_LDAP\\GroupPluginManager' => $baseDir . '/../lib/GroupPluginManager.php',
45
-    'OCA\\User_LDAP\\Group_LDAP' => $baseDir . '/../lib/Group_LDAP.php',
46
-    'OCA\\User_LDAP\\Group_Proxy' => $baseDir . '/../lib/Group_Proxy.php',
47
-    'OCA\\User_LDAP\\Handler\\ExtStorageConfigHandler' => $baseDir . '/../lib/Handler/ExtStorageConfigHandler.php',
48
-    'OCA\\User_LDAP\\Helper' => $baseDir . '/../lib/Helper.php',
49
-    'OCA\\User_LDAP\\IGroupLDAP' => $baseDir . '/../lib/IGroupLDAP.php',
50
-    'OCA\\User_LDAP\\ILDAPGroupPlugin' => $baseDir . '/../lib/ILDAPGroupPlugin.php',
51
-    'OCA\\User_LDAP\\ILDAPUserPlugin' => $baseDir . '/../lib/ILDAPUserPlugin.php',
52
-    'OCA\\User_LDAP\\ILDAPWrapper' => $baseDir . '/../lib/ILDAPWrapper.php',
53
-    'OCA\\User_LDAP\\IUserLDAP' => $baseDir . '/../lib/IUserLDAP.php',
54
-    'OCA\\User_LDAP\\Jobs\\CleanUp' => $baseDir . '/../lib/Jobs/CleanUp.php',
55
-    'OCA\\User_LDAP\\Jobs\\Sync' => $baseDir . '/../lib/Jobs/Sync.php',
56
-    'OCA\\User_LDAP\\Jobs\\UpdateGroups' => $baseDir . '/../lib/Jobs/UpdateGroups.php',
57
-    'OCA\\User_LDAP\\LDAP' => $baseDir . '/../lib/LDAP.php',
58
-    'OCA\\User_LDAP\\LDAPProvider' => $baseDir . '/../lib/LDAPProvider.php',
59
-    'OCA\\User_LDAP\\LDAPProviderFactory' => $baseDir . '/../lib/LDAPProviderFactory.php',
60
-    'OCA\\User_LDAP\\LDAPUtility' => $baseDir . '/../lib/LDAPUtility.php',
61
-    'OCA\\User_LDAP\\LoginListener' => $baseDir . '/../lib/LoginListener.php',
62
-    'OCA\\User_LDAP\\Mapping\\AbstractMapping' => $baseDir . '/../lib/Mapping/AbstractMapping.php',
63
-    'OCA\\User_LDAP\\Mapping\\GroupMapping' => $baseDir . '/../lib/Mapping/GroupMapping.php',
64
-    'OCA\\User_LDAP\\Mapping\\UserMapping' => $baseDir . '/../lib/Mapping/UserMapping.php',
65
-    'OCA\\User_LDAP\\Migration\\GroupMappingMigration' => $baseDir . '/../lib/Migration/GroupMappingMigration.php',
66
-    'OCA\\User_LDAP\\Migration\\RemoveRefreshTime' => $baseDir . '/../lib/Migration/RemoveRefreshTime.php',
67
-    'OCA\\User_LDAP\\Migration\\SetDefaultProvider' => $baseDir . '/../lib/Migration/SetDefaultProvider.php',
68
-    'OCA\\User_LDAP\\Migration\\UUIDFix' => $baseDir . '/../lib/Migration/UUIDFix.php',
69
-    'OCA\\User_LDAP\\Migration\\UUIDFixGroup' => $baseDir . '/../lib/Migration/UUIDFixGroup.php',
70
-    'OCA\\User_LDAP\\Migration\\UUIDFixInsert' => $baseDir . '/../lib/Migration/UUIDFixInsert.php',
71
-    'OCA\\User_LDAP\\Migration\\UUIDFixUser' => $baseDir . '/../lib/Migration/UUIDFixUser.php',
72
-    'OCA\\User_LDAP\\Migration\\UnsetDefaultProvider' => $baseDir . '/../lib/Migration/UnsetDefaultProvider.php',
73
-    'OCA\\User_LDAP\\Migration\\Version1010Date20200630192842' => $baseDir . '/../lib/Migration/Version1010Date20200630192842.php',
74
-    'OCA\\User_LDAP\\Migration\\Version1120Date20210917155206' => $baseDir . '/../lib/Migration/Version1120Date20210917155206.php',
75
-    'OCA\\User_LDAP\\Migration\\Version1130Date20211102154716' => $baseDir . '/../lib/Migration/Version1130Date20211102154716.php',
76
-    'OCA\\User_LDAP\\Migration\\Version1130Date20220110154717' => $baseDir . '/../lib/Migration/Version1130Date20220110154717.php',
77
-    'OCA\\User_LDAP\\Migration\\Version1130Date20220110154718' => $baseDir . '/../lib/Migration/Version1130Date20220110154718.php',
78
-    'OCA\\User_LDAP\\Migration\\Version1130Date20220110154719' => $baseDir . '/../lib/Migration/Version1130Date20220110154719.php',
79
-    'OCA\\User_LDAP\\Migration\\Version1141Date20220323143801' => $baseDir . '/../lib/Migration/Version1141Date20220323143801.php',
80
-    'OCA\\User_LDAP\\Migration\\Version1190Date20230706134108' => $baseDir . '/../lib/Migration/Version1190Date20230706134108.php',
81
-    'OCA\\User_LDAP\\Migration\\Version1190Date20230706134109' => $baseDir . '/../lib/Migration/Version1190Date20230706134109.php',
82
-    'OCA\\User_LDAP\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
83
-    'OCA\\User_LDAP\\PagedResults\\TLinkId' => $baseDir . '/../lib/PagedResults/TLinkId.php',
84
-    'OCA\\User_LDAP\\Proxy' => $baseDir . '/../lib/Proxy.php',
85
-    'OCA\\User_LDAP\\Service\\BirthdateParserService' => $baseDir . '/../lib/Service/BirthdateParserService.php',
86
-    'OCA\\User_LDAP\\Service\\UpdateGroupsService' => $baseDir . '/../lib/Service/UpdateGroupsService.php',
87
-    'OCA\\User_LDAP\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
88
-    'OCA\\User_LDAP\\Settings\\Section' => $baseDir . '/../lib/Settings/Section.php',
89
-    'OCA\\User_LDAP\\SetupChecks\\LdapConnection' => $baseDir . '/../lib/SetupChecks/LdapConnection.php',
90
-    'OCA\\User_LDAP\\SetupChecks\\LdapInvalidUuids' => $baseDir . '/../lib/SetupChecks/LdapInvalidUuids.php',
91
-    'OCA\\User_LDAP\\UserPluginManager' => $baseDir . '/../lib/UserPluginManager.php',
92
-    'OCA\\User_LDAP\\User\\DeletedUsersIndex' => $baseDir . '/../lib/User/DeletedUsersIndex.php',
93
-    'OCA\\User_LDAP\\User\\Manager' => $baseDir . '/../lib/User/Manager.php',
94
-    'OCA\\User_LDAP\\User\\OfflineUser' => $baseDir . '/../lib/User/OfflineUser.php',
95
-    'OCA\\User_LDAP\\User\\User' => $baseDir . '/../lib/User/User.php',
96
-    'OCA\\User_LDAP\\User_LDAP' => $baseDir . '/../lib/User_LDAP.php',
97
-    'OCA\\User_LDAP\\User_Proxy' => $baseDir . '/../lib/User_Proxy.php',
98
-    'OCA\\User_LDAP\\Wizard' => $baseDir . '/../lib/Wizard.php',
99
-    'OCA\\User_LDAP\\WizardFactory' => $baseDir . '/../lib/WizardFactory.php',
100
-    'OCA\\User_LDAP\\WizardResult' => $baseDir . '/../lib/WizardResult.php',
9
+    'Composer\\InstalledVersions' => $vendorDir.'/composer/InstalledVersions.php',
10
+    'OCA\\User_LDAP\\Access' => $baseDir.'/../lib/Access.php',
11
+    'OCA\\User_LDAP\\AccessFactory' => $baseDir.'/../lib/AccessFactory.php',
12
+    'OCA\\User_LDAP\\AppInfo\\Application' => $baseDir.'/../lib/AppInfo/Application.php',
13
+    'OCA\\User_LDAP\\BackendUtility' => $baseDir.'/../lib/BackendUtility.php',
14
+    'OCA\\User_LDAP\\Command\\CheckGroup' => $baseDir.'/../lib/Command/CheckGroup.php',
15
+    'OCA\\User_LDAP\\Command\\CheckUser' => $baseDir.'/../lib/Command/CheckUser.php',
16
+    'OCA\\User_LDAP\\Command\\CreateEmptyConfig' => $baseDir.'/../lib/Command/CreateEmptyConfig.php',
17
+    'OCA\\User_LDAP\\Command\\DeleteConfig' => $baseDir.'/../lib/Command/DeleteConfig.php',
18
+    'OCA\\User_LDAP\\Command\\PromoteGroup' => $baseDir.'/../lib/Command/PromoteGroup.php',
19
+    'OCA\\User_LDAP\\Command\\ResetGroup' => $baseDir.'/../lib/Command/ResetGroup.php',
20
+    'OCA\\User_LDAP\\Command\\ResetUser' => $baseDir.'/../lib/Command/ResetUser.php',
21
+    'OCA\\User_LDAP\\Command\\Search' => $baseDir.'/../lib/Command/Search.php',
22
+    'OCA\\User_LDAP\\Command\\SetConfig' => $baseDir.'/../lib/Command/SetConfig.php',
23
+    'OCA\\User_LDAP\\Command\\ShowConfig' => $baseDir.'/../lib/Command/ShowConfig.php',
24
+    'OCA\\User_LDAP\\Command\\ShowRemnants' => $baseDir.'/../lib/Command/ShowRemnants.php',
25
+    'OCA\\User_LDAP\\Command\\TestConfig' => $baseDir.'/../lib/Command/TestConfig.php',
26
+    'OCA\\User_LDAP\\Command\\TestUserSettings' => $baseDir.'/../lib/Command/TestUserSettings.php',
27
+    'OCA\\User_LDAP\\Command\\UpdateUUID' => $baseDir.'/../lib/Command/UpdateUUID.php',
28
+    'OCA\\User_LDAP\\Configuration' => $baseDir.'/../lib/Configuration.php',
29
+    'OCA\\User_LDAP\\Connection' => $baseDir.'/../lib/Connection.php',
30
+    'OCA\\User_LDAP\\ConnectionFactory' => $baseDir.'/../lib/ConnectionFactory.php',
31
+    'OCA\\User_LDAP\\Controller\\ConfigAPIController' => $baseDir.'/../lib/Controller/ConfigAPIController.php',
32
+    'OCA\\User_LDAP\\Controller\\RenewPasswordController' => $baseDir.'/../lib/Controller/RenewPasswordController.php',
33
+    'OCA\\User_LDAP\\Controller\\WizardController' => $baseDir.'/../lib/Controller/WizardController.php',
34
+    'OCA\\User_LDAP\\DataCollector\\LdapDataCollector' => $baseDir.'/../lib/DataCollector/LdapDataCollector.php',
35
+    'OCA\\User_LDAP\\Db\\GroupMembership' => $baseDir.'/../lib/Db/GroupMembership.php',
36
+    'OCA\\User_LDAP\\Db\\GroupMembershipMapper' => $baseDir.'/../lib/Db/GroupMembershipMapper.php',
37
+    'OCA\\User_LDAP\\Events\\GroupBackendRegistered' => $baseDir.'/../lib/Events/GroupBackendRegistered.php',
38
+    'OCA\\User_LDAP\\Events\\UserBackendRegistered' => $baseDir.'/../lib/Events/UserBackendRegistered.php',
39
+    'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => $baseDir.'/../lib/Exceptions/AttributeNotSet.php',
40
+    'OCA\\User_LDAP\\Exceptions\\ConfigurationIssueException' => $baseDir.'/../lib/Exceptions/ConfigurationIssueException.php',
41
+    'OCA\\User_LDAP\\Exceptions\\ConstraintViolationException' => $baseDir.'/../lib/Exceptions/ConstraintViolationException.php',
42
+    'OCA\\User_LDAP\\Exceptions\\NoMoreResults' => $baseDir.'/../lib/Exceptions/NoMoreResults.php',
43
+    'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => $baseDir.'/../lib/Exceptions/NotOnLDAP.php',
44
+    'OCA\\User_LDAP\\GroupPluginManager' => $baseDir.'/../lib/GroupPluginManager.php',
45
+    'OCA\\User_LDAP\\Group_LDAP' => $baseDir.'/../lib/Group_LDAP.php',
46
+    'OCA\\User_LDAP\\Group_Proxy' => $baseDir.'/../lib/Group_Proxy.php',
47
+    'OCA\\User_LDAP\\Handler\\ExtStorageConfigHandler' => $baseDir.'/../lib/Handler/ExtStorageConfigHandler.php',
48
+    'OCA\\User_LDAP\\Helper' => $baseDir.'/../lib/Helper.php',
49
+    'OCA\\User_LDAP\\IGroupLDAP' => $baseDir.'/../lib/IGroupLDAP.php',
50
+    'OCA\\User_LDAP\\ILDAPGroupPlugin' => $baseDir.'/../lib/ILDAPGroupPlugin.php',
51
+    'OCA\\User_LDAP\\ILDAPUserPlugin' => $baseDir.'/../lib/ILDAPUserPlugin.php',
52
+    'OCA\\User_LDAP\\ILDAPWrapper' => $baseDir.'/../lib/ILDAPWrapper.php',
53
+    'OCA\\User_LDAP\\IUserLDAP' => $baseDir.'/../lib/IUserLDAP.php',
54
+    'OCA\\User_LDAP\\Jobs\\CleanUp' => $baseDir.'/../lib/Jobs/CleanUp.php',
55
+    'OCA\\User_LDAP\\Jobs\\Sync' => $baseDir.'/../lib/Jobs/Sync.php',
56
+    'OCA\\User_LDAP\\Jobs\\UpdateGroups' => $baseDir.'/../lib/Jobs/UpdateGroups.php',
57
+    'OCA\\User_LDAP\\LDAP' => $baseDir.'/../lib/LDAP.php',
58
+    'OCA\\User_LDAP\\LDAPProvider' => $baseDir.'/../lib/LDAPProvider.php',
59
+    'OCA\\User_LDAP\\LDAPProviderFactory' => $baseDir.'/../lib/LDAPProviderFactory.php',
60
+    'OCA\\User_LDAP\\LDAPUtility' => $baseDir.'/../lib/LDAPUtility.php',
61
+    'OCA\\User_LDAP\\LoginListener' => $baseDir.'/../lib/LoginListener.php',
62
+    'OCA\\User_LDAP\\Mapping\\AbstractMapping' => $baseDir.'/../lib/Mapping/AbstractMapping.php',
63
+    'OCA\\User_LDAP\\Mapping\\GroupMapping' => $baseDir.'/../lib/Mapping/GroupMapping.php',
64
+    'OCA\\User_LDAP\\Mapping\\UserMapping' => $baseDir.'/../lib/Mapping/UserMapping.php',
65
+    'OCA\\User_LDAP\\Migration\\GroupMappingMigration' => $baseDir.'/../lib/Migration/GroupMappingMigration.php',
66
+    'OCA\\User_LDAP\\Migration\\RemoveRefreshTime' => $baseDir.'/../lib/Migration/RemoveRefreshTime.php',
67
+    'OCA\\User_LDAP\\Migration\\SetDefaultProvider' => $baseDir.'/../lib/Migration/SetDefaultProvider.php',
68
+    'OCA\\User_LDAP\\Migration\\UUIDFix' => $baseDir.'/../lib/Migration/UUIDFix.php',
69
+    'OCA\\User_LDAP\\Migration\\UUIDFixGroup' => $baseDir.'/../lib/Migration/UUIDFixGroup.php',
70
+    'OCA\\User_LDAP\\Migration\\UUIDFixInsert' => $baseDir.'/../lib/Migration/UUIDFixInsert.php',
71
+    'OCA\\User_LDAP\\Migration\\UUIDFixUser' => $baseDir.'/../lib/Migration/UUIDFixUser.php',
72
+    'OCA\\User_LDAP\\Migration\\UnsetDefaultProvider' => $baseDir.'/../lib/Migration/UnsetDefaultProvider.php',
73
+    'OCA\\User_LDAP\\Migration\\Version1010Date20200630192842' => $baseDir.'/../lib/Migration/Version1010Date20200630192842.php',
74
+    'OCA\\User_LDAP\\Migration\\Version1120Date20210917155206' => $baseDir.'/../lib/Migration/Version1120Date20210917155206.php',
75
+    'OCA\\User_LDAP\\Migration\\Version1130Date20211102154716' => $baseDir.'/../lib/Migration/Version1130Date20211102154716.php',
76
+    'OCA\\User_LDAP\\Migration\\Version1130Date20220110154717' => $baseDir.'/../lib/Migration/Version1130Date20220110154717.php',
77
+    'OCA\\User_LDAP\\Migration\\Version1130Date20220110154718' => $baseDir.'/../lib/Migration/Version1130Date20220110154718.php',
78
+    'OCA\\User_LDAP\\Migration\\Version1130Date20220110154719' => $baseDir.'/../lib/Migration/Version1130Date20220110154719.php',
79
+    'OCA\\User_LDAP\\Migration\\Version1141Date20220323143801' => $baseDir.'/../lib/Migration/Version1141Date20220323143801.php',
80
+    'OCA\\User_LDAP\\Migration\\Version1190Date20230706134108' => $baseDir.'/../lib/Migration/Version1190Date20230706134108.php',
81
+    'OCA\\User_LDAP\\Migration\\Version1190Date20230706134109' => $baseDir.'/../lib/Migration/Version1190Date20230706134109.php',
82
+    'OCA\\User_LDAP\\Notification\\Notifier' => $baseDir.'/../lib/Notification/Notifier.php',
83
+    'OCA\\User_LDAP\\PagedResults\\TLinkId' => $baseDir.'/../lib/PagedResults/TLinkId.php',
84
+    'OCA\\User_LDAP\\Proxy' => $baseDir.'/../lib/Proxy.php',
85
+    'OCA\\User_LDAP\\Service\\BirthdateParserService' => $baseDir.'/../lib/Service/BirthdateParserService.php',
86
+    'OCA\\User_LDAP\\Service\\UpdateGroupsService' => $baseDir.'/../lib/Service/UpdateGroupsService.php',
87
+    'OCA\\User_LDAP\\Settings\\Admin' => $baseDir.'/../lib/Settings/Admin.php',
88
+    'OCA\\User_LDAP\\Settings\\Section' => $baseDir.'/../lib/Settings/Section.php',
89
+    'OCA\\User_LDAP\\SetupChecks\\LdapConnection' => $baseDir.'/../lib/SetupChecks/LdapConnection.php',
90
+    'OCA\\User_LDAP\\SetupChecks\\LdapInvalidUuids' => $baseDir.'/../lib/SetupChecks/LdapInvalidUuids.php',
91
+    'OCA\\User_LDAP\\UserPluginManager' => $baseDir.'/../lib/UserPluginManager.php',
92
+    'OCA\\User_LDAP\\User\\DeletedUsersIndex' => $baseDir.'/../lib/User/DeletedUsersIndex.php',
93
+    'OCA\\User_LDAP\\User\\Manager' => $baseDir.'/../lib/User/Manager.php',
94
+    'OCA\\User_LDAP\\User\\OfflineUser' => $baseDir.'/../lib/User/OfflineUser.php',
95
+    'OCA\\User_LDAP\\User\\User' => $baseDir.'/../lib/User/User.php',
96
+    'OCA\\User_LDAP\\User_LDAP' => $baseDir.'/../lib/User_LDAP.php',
97
+    'OCA\\User_LDAP\\User_Proxy' => $baseDir.'/../lib/User_Proxy.php',
98
+    'OCA\\User_LDAP\\Wizard' => $baseDir.'/../lib/Wizard.php',
99
+    'OCA\\User_LDAP\\WizardFactory' => $baseDir.'/../lib/WizardFactory.php',
100
+    'OCA\\User_LDAP\\WizardResult' => $baseDir.'/../lib/WizardResult.php',
101 101
 );
Please login to merge, or discard this patch.
tests/lib/UrlGeneratorTest.php 1 patch
Indentation   +251 added lines, -251 removed lines patch added patch discarded remove patch
@@ -22,255 +22,255 @@
 block discarded – undo
22 22
  * @package Test
23 23
  */
24 24
 class UrlGeneratorTest extends \Test\TestCase {
25
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IConfig */
26
-	private $config;
27
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IUserSession */
28
-	private $userSession;
29
-	/** @var \PHPUnit\Framework\MockObject\MockObject|ICacheFactory */
30
-	private $cacheFactory;
31
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IRequest */
32
-	private $request;
33
-	/** @var \PHPUnit\Framework\MockObject\MockObject|Router */
34
-	private $router;
35
-	/** @var IURLGenerator */
36
-	private $urlGenerator;
37
-	/** @var string */
38
-	private $originalWebRoot;
39
-
40
-	protected function setUp(): void {
41
-		parent::setUp();
42
-		$this->config = $this->createMock(IConfig::class);
43
-		$this->userSession = $this->createMock(IUserSession::class);
44
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
45
-		$this->request = $this->createMock(IRequest::class);
46
-		$this->router = $this->createMock(Router::class);
47
-		$this->urlGenerator = new URLGenerator(
48
-			$this->config,
49
-			$this->userSession,
50
-			$this->cacheFactory,
51
-			$this->request,
52
-			$this->router
53
-		);
54
-		$this->originalWebRoot = \OC::$WEBROOT;
55
-	}
56
-
57
-	protected function tearDown(): void {
58
-		// Reset webRoot
59
-		\OC::$WEBROOT = $this->originalWebRoot;
60
-	}
61
-
62
-	private function mockBaseUrl() {
63
-		$this->request->expects($this->once())
64
-			->method('getServerProtocol')
65
-			->willReturn('http');
66
-		$this->request->expects($this->once())
67
-			->method('getServerHost')
68
-			->willReturn('localhost');
69
-	}
70
-
71
-	/**
72
-	 * test linkTo URL construction
73
-	 */
74
-	#[\PHPUnit\Framework\Attributes\DataProvider('provideDocRootAppUrlParts')]
75
-	public function testLinkToDocRoot($app, $file, $args, $expectedResult): void {
76
-		\OC::$WEBROOT = '';
77
-		$result = $this->urlGenerator->linkTo($app, $file, $args);
78
-		$this->assertEquals($expectedResult, $result);
79
-	}
80
-
81
-	/**
82
-	 * test linkTo URL construction in sub directory
83
-	 */
84
-	#[\PHPUnit\Framework\Attributes\DataProvider('provideSubDirAppUrlParts')]
85
-	public function testLinkToSubDir($app, $file, $args, $expectedResult): void {
86
-		\OC::$WEBROOT = '/nextcloud';
87
-		$result = $this->urlGenerator->linkTo($app, $file, $args);
88
-		$this->assertEquals($expectedResult, $result);
89
-	}
90
-
91
-	#[\PHPUnit\Framework\Attributes\DataProvider('provideRoutes')]
92
-	public function testLinkToRouteAbsolute($route, $expected): void {
93
-		$this->mockBaseUrl();
94
-		\OC::$WEBROOT = '/nextcloud';
95
-		$this->router->expects($this->once())
96
-			->method('generate')
97
-			->willReturnCallback(function ($routeName, $parameters) {
98
-				if ($routeName === 'core.Preview.getPreview') {
99
-					return '/index.php/core/preview.png';
100
-				} elseif ($routeName === 'cloud_federation_api.requesthandlercontroller.addShare') {
101
-					return '/index.php/ocm/shares';
102
-				}
103
-			});
104
-		$result = $this->urlGenerator->linkToRouteAbsolute($route);
105
-		$this->assertEquals($expected, $result);
106
-	}
107
-
108
-	public static function provideRoutes(): array {
109
-		return [
110
-			['core.Preview.getPreview', 'http://localhost/nextcloud/index.php/core/preview.png'],
111
-			['cloud_federation_api.requesthandlercontroller.addShare', 'http://localhost/nextcloud/index.php/ocm/shares'],
112
-		];
113
-	}
114
-
115
-	public static function provideDocRootAppUrlParts(): array {
116
-		return [
117
-			['testing', 'ajax/endpoint.php', [], '/index.php/apps/testing/ajax/endpoint.php'],
118
-			['testing', 'ajax/endpoint.php', ['trut' => 'trat', 'dut' => 'dat'], '/index.php/apps/testing/ajax/endpoint.php?trut=trat&dut=dat'],
119
-			['', 'index.php', ['trut' => 'trat', 'dut' => 'dat'], '/index.php?trut=trat&dut=dat'],
120
-		];
121
-	}
122
-
123
-	public static function provideSubDirAppUrlParts(): array {
124
-		return [
125
-			['testing', 'ajax/endpoint.php', [], '/nextcloud/index.php/apps/testing/ajax/endpoint.php'],
126
-			['testing', 'ajax/endpoint.php', ['trut' => 'trat', 'dut' => 'dat'], '/nextcloud/index.php/apps/testing/ajax/endpoint.php?trut=trat&dut=dat'],
127
-			['', 'index.php', ['trut' => 'trat', 'dut' => 'dat'], '/nextcloud/index.php?trut=trat&dut=dat'],
128
-		];
129
-	}
130
-
131
-	/**
132
-	 * test absolute URL construction
133
-	 */
134
-	#[\PHPUnit\Framework\Attributes\DataProvider('provideDocRootURLs')]
135
-	public function testGetAbsoluteURLDocRoot($url, $expectedResult): void {
136
-		$this->mockBaseUrl();
137
-		\OC::$WEBROOT = '';
138
-		$result = $this->urlGenerator->getAbsoluteURL($url);
139
-		$this->assertEquals($expectedResult, $result);
140
-	}
141
-
142
-	/**
143
-	 * test absolute URL construction
144
-	 */
145
-	#[\PHPUnit\Framework\Attributes\DataProvider('provideSubDirURLs')]
146
-	public function testGetAbsoluteURLSubDir($url, $expectedResult): void {
147
-		$this->mockBaseUrl();
148
-		\OC::$WEBROOT = '/nextcloud';
149
-		$result = $this->urlGenerator->getAbsoluteURL($url);
150
-		$this->assertEquals($expectedResult, $result);
151
-	}
152
-
153
-	public static function provideDocRootURLs(): array {
154
-		return [
155
-			['index.php', 'http://localhost/index.php'],
156
-			['/index.php', 'http://localhost/index.php'],
157
-			['/apps/index.php', 'http://localhost/apps/index.php'],
158
-			['apps/index.php', 'http://localhost/apps/index.php'],
159
-		];
160
-	}
161
-
162
-	public static function provideSubDirURLs(): array {
163
-		return [
164
-			['', 'http://localhost/nextcloud/'],
165
-			['/', 'http://localhost/nextcloud/'],
166
-			['index.php', 'http://localhost/nextcloud/index.php'],
167
-			['/index.php', 'http://localhost/nextcloud/index.php'],
168
-			['/apps/index.php', 'http://localhost/nextcloud/apps/index.php'],
169
-			['apps/index.php', 'http://localhost/nextcloud/apps/index.php'],
170
-		];
171
-	}
172
-
173
-	public function testGetBaseUrl(): void {
174
-		$this->mockBaseUrl();
175
-		\OC::$WEBROOT = '/nextcloud';
176
-		$actual = $this->urlGenerator->getBaseUrl();
177
-		$expected = 'http://localhost/nextcloud';
178
-		$this->assertEquals($expected, $actual);
179
-	}
180
-
181
-	public function testGetWebroot(): void {
182
-		\OC::$WEBROOT = '/nextcloud';
183
-		$actual = $this->urlGenerator->getWebroot();
184
-		$this->assertEquals(\OC::$WEBROOT, $actual);
185
-	}
186
-
187
-	#[\PHPUnit\Framework\Attributes\DataProvider('provideOCSRoutes')]
188
-	public function testLinkToOCSRouteAbsolute(string $route, bool $ignoreFrontController, string $expected): void {
189
-		$this->mockBaseUrl();
190
-		\OC::$WEBROOT = '/nextcloud';
191
-		$this->router->expects($this->once())
192
-			->method('generate')
193
-			->willReturnCallback(function (string $routeName, array $parameters) use ($ignoreFrontController) {
194
-				if ($routeName === 'ocs.core.OCS.getCapabilities') {
195
-					if (!$ignoreFrontController) {
196
-						return '/nextcloud/index.php/ocsapp/cloud/capabilities';
197
-					}
198
-					return '/nextcloud/ocsapp/cloud/capabilities';
199
-				} elseif ($routeName === 'ocs.core.WhatsNew.dismiss') {
200
-					if (!$ignoreFrontController) {
201
-						return '/nextcloud/index.php/ocsapp/core/whatsnew';
202
-					}
203
-					return '/nextcloud/ocsapp/core/whatsnew';
204
-				}
205
-			});
206
-		$result = $this->urlGenerator->linkToOCSRouteAbsolute($route);
207
-		$this->assertEquals($expected, $result);
208
-	}
209
-
210
-	public static function provideOCSRoutes(): array {
211
-		return [
212
-			['core.OCS.getCapabilities', false, 'http://localhost/nextcloud/ocs/v2.php/cloud/capabilities'],
213
-			['core.OCS.getCapabilities', true, 'http://localhost/nextcloud/ocs/v2.php/cloud/capabilities'],
214
-			['core.WhatsNew.dismiss', false, 'http://localhost/nextcloud/ocs/v2.php/core/whatsnew'],
215
-			['core.WhatsNew.dismiss', true, 'http://localhost/nextcloud/ocs/v2.php/core/whatsnew'],
216
-		];
217
-	}
218
-
219
-	private function mockLinkToDefaultPageUrl(bool $ignoreFrontControllerConfig = false) {
220
-		$this->config->expects($this->once())
221
-			->method('getAppValue')
222
-			->with('core', 'defaultpage')
223
-			->willReturn('');
224
-
225
-		$this->config->expects($this->once())
226
-			->method('getSystemValueBool')
227
-			->with('htaccess.IgnoreFrontController', $this->anything())
228
-			->willReturn($ignoreFrontControllerConfig);
229
-	}
230
-
231
-	public function testLinkToDefaultPageUrlWithRedirectUrlWithoutFrontController(): void {
232
-		$this->mockBaseUrl();
233
-
234
-		$_REQUEST['redirect_url'] = 'myRedirectUrl.com';
235
-		$this->assertSame('http://localhost' . \OC::$WEBROOT . '/myRedirectUrl.com', $this->urlGenerator->linkToDefaultPageUrl());
236
-	}
237
-
238
-	public function testLinkToDefaultPageUrlWithRedirectUrlRedirectBypassWithoutFrontController(): void {
239
-		$this->mockBaseUrl();
240
-		$this->mockLinkToDefaultPageUrl();
241
-		putenv('front_controller_active=false');
242
-
243
-		$_REQUEST['redirect_url'] = '[email protected]:a';
244
-		$this->assertSame('http://localhost' . \OC::$WEBROOT . '/index.php/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl());
245
-	}
246
-
247
-	public function testLinkToDefaultPageUrlWithRedirectUrlRedirectBypassWithFrontController(): void {
248
-		$this->mockBaseUrl();
249
-		$this->mockLinkToDefaultPageUrl();
250
-		putenv('front_controller_active=true');
251
-
252
-		$_REQUEST['redirect_url'] = '[email protected]:a';
253
-		$this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl());
254
-	}
255
-
256
-	public function testLinkToDefaultPageUrlWithRedirectUrlWithIgnoreFrontController(): void {
257
-		$this->mockBaseUrl();
258
-		$this->mockLinkToDefaultPageUrl(true);
259
-		putenv('front_controller_active=false');
260
-
261
-		$_REQUEST['redirect_url'] = '[email protected]:a';
262
-		$this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl());
263
-	}
264
-
265
-	public static function imagePathProvider(): array {
266
-		return [
267
-			['core', 'favicon-mask.svg', \OC::$WEBROOT . '/core/img/favicon-mask.svg'],
268
-			['files', 'folder.svg', \OC::$WEBROOT . '/apps/files/img/folder.svg'],
269
-		];
270
-	}
271
-
272
-	#[\PHPUnit\Framework\Attributes\DataProvider('imagePathProvider')]
273
-	public function testImagePath(string $appName, string $file, string $result): void {
274
-		$this->assertSame($result, $this->urlGenerator->imagePath($appName, $file));
275
-	}
25
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IConfig */
26
+    private $config;
27
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IUserSession */
28
+    private $userSession;
29
+    /** @var \PHPUnit\Framework\MockObject\MockObject|ICacheFactory */
30
+    private $cacheFactory;
31
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IRequest */
32
+    private $request;
33
+    /** @var \PHPUnit\Framework\MockObject\MockObject|Router */
34
+    private $router;
35
+    /** @var IURLGenerator */
36
+    private $urlGenerator;
37
+    /** @var string */
38
+    private $originalWebRoot;
39
+
40
+    protected function setUp(): void {
41
+        parent::setUp();
42
+        $this->config = $this->createMock(IConfig::class);
43
+        $this->userSession = $this->createMock(IUserSession::class);
44
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
45
+        $this->request = $this->createMock(IRequest::class);
46
+        $this->router = $this->createMock(Router::class);
47
+        $this->urlGenerator = new URLGenerator(
48
+            $this->config,
49
+            $this->userSession,
50
+            $this->cacheFactory,
51
+            $this->request,
52
+            $this->router
53
+        );
54
+        $this->originalWebRoot = \OC::$WEBROOT;
55
+    }
56
+
57
+    protected function tearDown(): void {
58
+        // Reset webRoot
59
+        \OC::$WEBROOT = $this->originalWebRoot;
60
+    }
61
+
62
+    private function mockBaseUrl() {
63
+        $this->request->expects($this->once())
64
+            ->method('getServerProtocol')
65
+            ->willReturn('http');
66
+        $this->request->expects($this->once())
67
+            ->method('getServerHost')
68
+            ->willReturn('localhost');
69
+    }
70
+
71
+    /**
72
+     * test linkTo URL construction
73
+     */
74
+    #[\PHPUnit\Framework\Attributes\DataProvider('provideDocRootAppUrlParts')]
75
+    public function testLinkToDocRoot($app, $file, $args, $expectedResult): void {
76
+        \OC::$WEBROOT = '';
77
+        $result = $this->urlGenerator->linkTo($app, $file, $args);
78
+        $this->assertEquals($expectedResult, $result);
79
+    }
80
+
81
+    /**
82
+     * test linkTo URL construction in sub directory
83
+     */
84
+    #[\PHPUnit\Framework\Attributes\DataProvider('provideSubDirAppUrlParts')]
85
+    public function testLinkToSubDir($app, $file, $args, $expectedResult): void {
86
+        \OC::$WEBROOT = '/nextcloud';
87
+        $result = $this->urlGenerator->linkTo($app, $file, $args);
88
+        $this->assertEquals($expectedResult, $result);
89
+    }
90
+
91
+    #[\PHPUnit\Framework\Attributes\DataProvider('provideRoutes')]
92
+    public function testLinkToRouteAbsolute($route, $expected): void {
93
+        $this->mockBaseUrl();
94
+        \OC::$WEBROOT = '/nextcloud';
95
+        $this->router->expects($this->once())
96
+            ->method('generate')
97
+            ->willReturnCallback(function ($routeName, $parameters) {
98
+                if ($routeName === 'core.Preview.getPreview') {
99
+                    return '/index.php/core/preview.png';
100
+                } elseif ($routeName === 'cloud_federation_api.requesthandlercontroller.addShare') {
101
+                    return '/index.php/ocm/shares';
102
+                }
103
+            });
104
+        $result = $this->urlGenerator->linkToRouteAbsolute($route);
105
+        $this->assertEquals($expected, $result);
106
+    }
107
+
108
+    public static function provideRoutes(): array {
109
+        return [
110
+            ['core.Preview.getPreview', 'http://localhost/nextcloud/index.php/core/preview.png'],
111
+            ['cloud_federation_api.requesthandlercontroller.addShare', 'http://localhost/nextcloud/index.php/ocm/shares'],
112
+        ];
113
+    }
114
+
115
+    public static function provideDocRootAppUrlParts(): array {
116
+        return [
117
+            ['testing', 'ajax/endpoint.php', [], '/index.php/apps/testing/ajax/endpoint.php'],
118
+            ['testing', 'ajax/endpoint.php', ['trut' => 'trat', 'dut' => 'dat'], '/index.php/apps/testing/ajax/endpoint.php?trut=trat&dut=dat'],
119
+            ['', 'index.php', ['trut' => 'trat', 'dut' => 'dat'], '/index.php?trut=trat&dut=dat'],
120
+        ];
121
+    }
122
+
123
+    public static function provideSubDirAppUrlParts(): array {
124
+        return [
125
+            ['testing', 'ajax/endpoint.php', [], '/nextcloud/index.php/apps/testing/ajax/endpoint.php'],
126
+            ['testing', 'ajax/endpoint.php', ['trut' => 'trat', 'dut' => 'dat'], '/nextcloud/index.php/apps/testing/ajax/endpoint.php?trut=trat&dut=dat'],
127
+            ['', 'index.php', ['trut' => 'trat', 'dut' => 'dat'], '/nextcloud/index.php?trut=trat&dut=dat'],
128
+        ];
129
+    }
130
+
131
+    /**
132
+     * test absolute URL construction
133
+     */
134
+    #[\PHPUnit\Framework\Attributes\DataProvider('provideDocRootURLs')]
135
+    public function testGetAbsoluteURLDocRoot($url, $expectedResult): void {
136
+        $this->mockBaseUrl();
137
+        \OC::$WEBROOT = '';
138
+        $result = $this->urlGenerator->getAbsoluteURL($url);
139
+        $this->assertEquals($expectedResult, $result);
140
+    }
141
+
142
+    /**
143
+     * test absolute URL construction
144
+     */
145
+    #[\PHPUnit\Framework\Attributes\DataProvider('provideSubDirURLs')]
146
+    public function testGetAbsoluteURLSubDir($url, $expectedResult): void {
147
+        $this->mockBaseUrl();
148
+        \OC::$WEBROOT = '/nextcloud';
149
+        $result = $this->urlGenerator->getAbsoluteURL($url);
150
+        $this->assertEquals($expectedResult, $result);
151
+    }
152
+
153
+    public static function provideDocRootURLs(): array {
154
+        return [
155
+            ['index.php', 'http://localhost/index.php'],
156
+            ['/index.php', 'http://localhost/index.php'],
157
+            ['/apps/index.php', 'http://localhost/apps/index.php'],
158
+            ['apps/index.php', 'http://localhost/apps/index.php'],
159
+        ];
160
+    }
161
+
162
+    public static function provideSubDirURLs(): array {
163
+        return [
164
+            ['', 'http://localhost/nextcloud/'],
165
+            ['/', 'http://localhost/nextcloud/'],
166
+            ['index.php', 'http://localhost/nextcloud/index.php'],
167
+            ['/index.php', 'http://localhost/nextcloud/index.php'],
168
+            ['/apps/index.php', 'http://localhost/nextcloud/apps/index.php'],
169
+            ['apps/index.php', 'http://localhost/nextcloud/apps/index.php'],
170
+        ];
171
+    }
172
+
173
+    public function testGetBaseUrl(): void {
174
+        $this->mockBaseUrl();
175
+        \OC::$WEBROOT = '/nextcloud';
176
+        $actual = $this->urlGenerator->getBaseUrl();
177
+        $expected = 'http://localhost/nextcloud';
178
+        $this->assertEquals($expected, $actual);
179
+    }
180
+
181
+    public function testGetWebroot(): void {
182
+        \OC::$WEBROOT = '/nextcloud';
183
+        $actual = $this->urlGenerator->getWebroot();
184
+        $this->assertEquals(\OC::$WEBROOT, $actual);
185
+    }
186
+
187
+    #[\PHPUnit\Framework\Attributes\DataProvider('provideOCSRoutes')]
188
+    public function testLinkToOCSRouteAbsolute(string $route, bool $ignoreFrontController, string $expected): void {
189
+        $this->mockBaseUrl();
190
+        \OC::$WEBROOT = '/nextcloud';
191
+        $this->router->expects($this->once())
192
+            ->method('generate')
193
+            ->willReturnCallback(function (string $routeName, array $parameters) use ($ignoreFrontController) {
194
+                if ($routeName === 'ocs.core.OCS.getCapabilities') {
195
+                    if (!$ignoreFrontController) {
196
+                        return '/nextcloud/index.php/ocsapp/cloud/capabilities';
197
+                    }
198
+                    return '/nextcloud/ocsapp/cloud/capabilities';
199
+                } elseif ($routeName === 'ocs.core.WhatsNew.dismiss') {
200
+                    if (!$ignoreFrontController) {
201
+                        return '/nextcloud/index.php/ocsapp/core/whatsnew';
202
+                    }
203
+                    return '/nextcloud/ocsapp/core/whatsnew';
204
+                }
205
+            });
206
+        $result = $this->urlGenerator->linkToOCSRouteAbsolute($route);
207
+        $this->assertEquals($expected, $result);
208
+    }
209
+
210
+    public static function provideOCSRoutes(): array {
211
+        return [
212
+            ['core.OCS.getCapabilities', false, 'http://localhost/nextcloud/ocs/v2.php/cloud/capabilities'],
213
+            ['core.OCS.getCapabilities', true, 'http://localhost/nextcloud/ocs/v2.php/cloud/capabilities'],
214
+            ['core.WhatsNew.dismiss', false, 'http://localhost/nextcloud/ocs/v2.php/core/whatsnew'],
215
+            ['core.WhatsNew.dismiss', true, 'http://localhost/nextcloud/ocs/v2.php/core/whatsnew'],
216
+        ];
217
+    }
218
+
219
+    private function mockLinkToDefaultPageUrl(bool $ignoreFrontControllerConfig = false) {
220
+        $this->config->expects($this->once())
221
+            ->method('getAppValue')
222
+            ->with('core', 'defaultpage')
223
+            ->willReturn('');
224
+
225
+        $this->config->expects($this->once())
226
+            ->method('getSystemValueBool')
227
+            ->with('htaccess.IgnoreFrontController', $this->anything())
228
+            ->willReturn($ignoreFrontControllerConfig);
229
+    }
230
+
231
+    public function testLinkToDefaultPageUrlWithRedirectUrlWithoutFrontController(): void {
232
+        $this->mockBaseUrl();
233
+
234
+        $_REQUEST['redirect_url'] = 'myRedirectUrl.com';
235
+        $this->assertSame('http://localhost' . \OC::$WEBROOT . '/myRedirectUrl.com', $this->urlGenerator->linkToDefaultPageUrl());
236
+    }
237
+
238
+    public function testLinkToDefaultPageUrlWithRedirectUrlRedirectBypassWithoutFrontController(): void {
239
+        $this->mockBaseUrl();
240
+        $this->mockLinkToDefaultPageUrl();
241
+        putenv('front_controller_active=false');
242
+
243
+        $_REQUEST['redirect_url'] = '[email protected]:a';
244
+        $this->assertSame('http://localhost' . \OC::$WEBROOT . '/index.php/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl());
245
+    }
246
+
247
+    public function testLinkToDefaultPageUrlWithRedirectUrlRedirectBypassWithFrontController(): void {
248
+        $this->mockBaseUrl();
249
+        $this->mockLinkToDefaultPageUrl();
250
+        putenv('front_controller_active=true');
251
+
252
+        $_REQUEST['redirect_url'] = '[email protected]:a';
253
+        $this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl());
254
+    }
255
+
256
+    public function testLinkToDefaultPageUrlWithRedirectUrlWithIgnoreFrontController(): void {
257
+        $this->mockBaseUrl();
258
+        $this->mockLinkToDefaultPageUrl(true);
259
+        putenv('front_controller_active=false');
260
+
261
+        $_REQUEST['redirect_url'] = '[email protected]:a';
262
+        $this->assertSame('http://localhost' . \OC::$WEBROOT . '/apps/dashboard/', $this->urlGenerator->linkToDefaultPageUrl());
263
+    }
264
+
265
+    public static function imagePathProvider(): array {
266
+        return [
267
+            ['core', 'favicon-mask.svg', \OC::$WEBROOT . '/core/img/favicon-mask.svg'],
268
+            ['files', 'folder.svg', \OC::$WEBROOT . '/apps/files/img/folder.svg'],
269
+        ];
270
+    }
271
+
272
+    #[\PHPUnit\Framework\Attributes\DataProvider('imagePathProvider')]
273
+    public function testImagePath(string $appName, string $file, string $result): void {
274
+        $this->assertSame($result, $this->urlGenerator->imagePath($appName, $file));
275
+    }
276 276
 }
Please login to merge, or discard this patch.