Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (2023)

1
<?php
2
/**
3
 * ---------------------------------------------------------------------
4
 * GLPI - Gestionnaire Libre de Parc Informatique
5
 * Copyright (C) 2015-2021 Teclib' and contributors.
6
 *
7
 * http://glpi-project.org
8
 *
9
 * based on GLPI - Gestionnaire Libre de Parc Informatique
10
 * Copyright (C) 2003-2014 by the INDEPNET Development Team.
11
 *
12
 * ---------------------------------------------------------------------
13
 *
14
 * LICENSE
15
 *
16
 * This file is part of GLPI.
17
 *
18
 * GLPI is free software; you can redistribute it and/or modify
19
 * it under the terms of the GNU General Public License as published by
20
 * the Free Software Foundation; either version 2 of the License, or
21
 * (at your option) any later version.
22
 *
23
 * GLPI is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
29
 * along with GLPI. If not, see <http://www.gnu.org/licenses/>.
30
 * ---------------------------------------------------------------------
31
 */
32
33
/**
34
 * Class used to manage Auth LDAP config
35
 */
36
class AuthLDAP extends CommonDBTM {
37
38
 const SIMPLE_INTERFACE = 'simple';
39
 const EXPERT_INTERFACE = 'expert';
40
41
 const ACTION_IMPORT = 0;
42
 const ACTION_SYNCHRONIZE = 1;
43
 const ACTION_ALL = 2;
44
45
 const USER_IMPORTED = 0;
46
 const USER_SYNCHRONIZED = 1;
47
 const USER_DELETED_LDAP = 2;
48
49
 //Import user by giving his login
50
 const IDENTIFIER_LOGIN = 'login';
51
52
 //Import user by giving his email
53
 const IDENTIFIER_EMAIL = 'email';
54
55
 const GROUP_SEARCH_USER = 0;
56
 const GROUP_SEARCH_GROUP = 1;
57
 const GROUP_SEARCH_BOTH = 2;
58
59
 /**
60
 * Deleted user strategy: preserve user.
61
 * @var integer
62
 */
63
 const DELETED_USER_PRESERVE = 0;
64
65
 /**
66
 * Deleted user strategy: put user in trashbin.
67
 * @var integer
68
 */
69
 const DELETED_USER_DELETE = 1;
70
71
 /**
72
 * Deleted user strategy: withdraw dynamic authorizations and groups.
73
 * @var integer
74
 */
75
 const DELETED_USER_WITHDRAWDYNINFO = 2;
76
77
 /**
78
 * Deleted user strategy: disable user.
79
 * @var integer
80
 */
81
 const DELETED_USER_DISABLE = 3;
82
83
 /**
84
 * Deleted user strategy: disable user and withdraw dynamic authorizations and groups.
85
 * @var integer
86
 */
87
 const DELETED_USER_DISABLEANDWITHDRAWDYNINFO = 4;
88
89
 // From CommonDBTM
90
 public $dohistory = true;
91
92
 static $rightname = 'config';
93
94
 //connection caching stuff
95
 static $conn_cache = [];
96
97
 static $undisclosedFields = [
98
 'rootdn_passwd',
99
 ];
100
101
 static function getTypeName($nb = 0) {
102
 return _n('LDAP directory', 'LDAP directories', $nb);
103
 }
104
105
 static function canCreate() {
106
 return static::canUpdate();
107
 }
108
109
 static function canPurge() {
110
 return static::canUpdate();
111
 }
112
113
 function post_getEmpty() {
114
115
 $this->fields['port'] = '389';
116
 $this->fields['condition'] = '';
117
 $this->fields['login_field'] = 'uid';
118
 $this->fields['sync_field'] = null;
119
 $this->fields['use_tls'] = 0;
120
 $this->fields['group_field'] = '';
121
 $this->fields['group_condition'] = '';
122
 $this->fields['group_search_type'] = self::GROUP_SEARCH_USER;
123
 $this->fields['group_member_field'] = '';
124
 $this->fields['email1_field'] = 'mail';
125
 $this->fields['email2_field'] = '';
126
 $this->fields['email3_field'] = '';
127
 $this->fields['email4_field'] = '';
128
 $this->fields['realname_field'] = 'sn';
129
 $this->fields['firstname_field'] = 'givenname';
130
 $this->fields['phone_field'] = 'telephonenumber';
131
 $this->fields['phone2_field'] = '';
132
 $this->fields['mobile_field'] = '';
133
 $this->fields['registration_number_field'] = '';
134
 $this->fields['comment_field'] = '';
135
 $this->fields['title_field'] = '';
136
 $this->fields['use_dn'] = 0;
137
 $this->fields['picture_field'] = '';
138
 $this->fields['responsible_field'] = '';
139
 }
140
141
142
 /**
143
 * Preconfig datas for standard system
144
 *
145
 * @param string $type type of standard system : AD
146
 *
147
 * @return void
148
 */
149
 function preconfig($type) {
150
151
 switch ($type) {
152
 case 'AD' :
153
 $this->fields['port'] = "389";
154
 $this->fields['condition']
155
 = '(&(objectClass=user)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))';
156
 $this->fields['login_field'] = 'samaccountname';
157
 $this->fields['sync_field'] = 'objectguid';
158
 $this->fields['use_tls'] = 0;
159
 $this->fields['group_field'] = 'memberof';
160
 $this->fields['group_condition']
161
 = '(&(objectClass=user)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))';
162
 $this->fields['group_search_type'] = self::GROUP_SEARCH_USER;
163
 $this->fields['group_member_field'] = '';
164
 $this->fields['email1_field'] = 'mail';
165
 $this->fields['email2_field'] = '';
166
 $this->fields['email3_field'] = '';
167
 $this->fields['email4_field'] = '';
168
 $this->fields['realname_field'] = 'sn';
169
 $this->fields['firstname_field'] = 'givenname';
170
 $this->fields['phone_field'] = 'telephonenumber';
171
 $this->fields['phone2_field'] = 'othertelephone';
172
 $this->fields['mobile_field'] = 'mobile';
173
 $this->fields['registration_number_field'] = 'employeenumber';
174
 $this->fields['comment_field'] = 'info';
175
 $this->fields['title_field'] = 'title';
176
 $this->fields['entity_field'] = 'ou';
177
 $this->fields['entity_condition'] = '(objectclass=organizationalUnit)';
178
 $this->fields['use_dn'] = 1;
179
 $this->fields['can_support_pagesize'] = 1;
180
 $this->fields['pagesize'] = '1000';
181
 $this->fields['picture_field'] = '';
182
 $this->fields['responsible_field'] = 'manager';
183
 break;
184
185
 default:
186
 $this->post_getEmpty();
187
 }
188
 }
189
190
 function prepareInputForUpdate($input) {
191
192
 if (isset($input["rootdn_passwd"])) {
193
 if (empty($input["rootdn_passwd"])) {
194
 unset($input["rootdn_passwd"]);
195
 } else {
196
 $input["rootdn_passwd"] = Toolbox::sodiumEncrypt($input["rootdn_passwd"]);
197
 }
198
 }
199
200
 if (isset($input["_blank_passwd"]) && $input["_blank_passwd"]) {
201
 $input['rootdn_passwd'] = '';
202
 }
203
204
 // Set attributes in lower case
205
 if (count($input)) {
206
 foreach ($input as $key => $val) {
207
 if (preg_match('/_field$/', $key)) {
208
 $input[$key] = Toolbox::strtolower($val);
209
 }
210
 }
211
 }
212
213
 //do not permit to override sync_field
214
 if ($this->isSyncFieldEnabled()
215
 && isset($input['sync_field'])
216
 && $this->isSyncFieldUsed()
217
 ) {
218
 if ($input['sync_field'] == $this->fields['sync_field']) {
219
 unset($input['sync_field']);
220
 } else {
221
 Session::addMessageAfterRedirect(
222
 __('Synchronization field cannot be changed once in use.'),
223
 false,
224
 ERROR
225
 );
226
 return false;
227
 };
228
 }
229
 return $input;
230
 }
231
232
 static function getSpecificValueToDisplay($field, $values, array $options = []) {
233
234
 if (!is_array($values)) {
235
 $values = [$field => $values];
236
 }
237
 switch ($field) {
238
 case 'group_search_type' :
239
 return self::getGroupSearchTypeName($values[$field]);
240
 }
241
 return parent::getSpecificValueToDisplay($field, $values, $options);
242
 }
243
244
 static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) {
245
246
 if (!is_array($values)) {
247
 $values = [$field => $values];
248
 }
249
 $options['display'] = false;
250
 switch ($field) {
251
 case 'group_search_type' :
252
 $options['value'] = $values[$field];
253
 $options['name'] = $name;
254
 return self::dropdownGroupSearchType($options);
255
 }
256
 return parent::getSpecificValueToSelect($field, $name, $values, $options);
257
 }
258
259
 static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, array $ids) {
260
 $input = $ma->getInput();
261
262
 switch ($ma->getAction()) {
263
 case 'import_group' :
264
 $group = new Group;
265
 if (!Session::haveRight("user", User::UPDATEAUTHENT)
266
 || !$group->canGlobal(UPDATE)) {
267
 $ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_NORIGHT);
268
 $ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
269
 return;
270
 }
271
 foreach ($ids as $id) {
272
 if (isset($input["dn"][$id])) {
273
 $group_dn = $input["dn"][$id];
274
 if (isset($input["ldap_import_entities"][$id])) {
275
 $entity = $input["ldap_import_entities"][$id];
276
 } else {
277
 $entity = $_SESSION["glpiactive_entity"];
278
 }
279
 // Is recursive is in the main form and thus, don't pass through
280
 // zero_on_empty mechanism inside massive action form ...
281
 $is_recursive = (empty($input['ldap_import_recursive'][$id]) ? 0 : 1);
282
 $options = ['authldaps_id' => $_SESSION['ldap_server'],
283
 'entities_id' => $entity,
284
 'is_recursive' => $is_recursive,
285
 'type' => $input['ldap_import_type'][$id]];
286
 if (AuthLDAP::ldapImportGroup($group_dn, $options)) {
287
 $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
288
 } else {
289
 $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
290
 $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION, $group_dn));
291
 }
292
 }
293
 // Clean history as id does not correspond to group
294
 $_SESSION['glpimassiveactionselected'] = [];
295
 }
296
 return;
297
298
 case 'import' :
299
 case 'sync' :
300
 if (!Session::haveRight("user", User::IMPORTEXTAUTHUSERS)) {
301
 $ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_NORIGHT);
302
 $ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
303
 return;
304
 }
305
 foreach ($ids as $id) {
306
 if (AuthLDAP::ldapImportUserByServerId(['method' => AuthLDAP::IDENTIFIER_LOGIN,
307
 'value' => $id],
308
 $_SESSION['ldap_import']['mode'],
309
 $_SESSION['ldap_import']['authldaps_id'],
310
 true)) {
311
 $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
312
 } else {
313
 $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
314
 $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION, $id));
315
 }
316
 }
317
 return;
318
 }
319
320
 parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
321
 }
322
323
 /**
324
 * Print the auth ldap form
325
 *
326
 * @param integer $ID ID of the item
327
 * @param array $options Options
328
 * - target for the form
329
 *
330
 * @return void|boolean (display) Returns false if there is a rights error.
331
 */
332
 function showForm($ID, $options = []) {
333
334
 if (!Config::canUpdate()) {
335
 return false;
336
 }
337
 if (empty($ID)) {
338
 $this->getEmpty();
339
 if (isset($options['preconfig'])) {
340
 $this->preconfig($options['preconfig']);
341
 }
342
 } else {
343
 $this->getFromDB($ID);
344
 }
345
346
 if (Toolbox::canUseLdap()) {
347
 $this->showFormHeader($options);
348
 if (empty($ID)) {
349
 $target = $this->getFormURL();
350
 echo "<tr class='tab_bg_2'><td>".__('Preconfiguration')."</td> ";
351
 echo "<td colspan='3'>";
352
 echo "<a href='$target?preconfig=AD'>".__('Active Directory')."</a>";
353
 echo "&nbsp;&nbsp;/&nbsp;&nbsp;";
354
 echo "<a href='$target?preconfig=default'>".__('Default values');
355
 echo "</a></td></tr>";
356
 }
357
 echo "<tr class='tab_bg_1'><td><label for='name'>" . __('Name') . "</label></td>";
358
 echo "<td><input type='text' id='name' name='name' value='". $this->fields["name"] ."'></td>";
359
 if ($ID > 0) {
360
 echo "<td>".__('Last update')."</td><td>".Html::convDateTime($this->fields["date_mod"]);
361
 } else {
362
 echo "<td colspan='2'>&nbsp;";
363
 }
364
 echo "</td></tr>";
365
366
 $defaultrand = mt_rand();
367
 echo "<tr class='tab_bg_1'><td><label for='dropdown_is_default$defaultrand'>" . __('Default server') . "</label></td>";
368
 echo "<td>";
369
 Dropdown::showYesNo('is_default', $this->fields['is_default'], -1, ['rand' => $defaultrand]);
370
 echo "</td>";
371
 $activerand = mt_rand();
372
 echo "<td><label for='dropdown_is_active$activerand'>" . __('Active'). "</label></td>";
373
 echo "<td>";
374
 Dropdown::showYesNo('is_active', $this->fields['is_active'], -1, ['rand' => $activerand]);
375
 echo "</td></tr>";
376
377
 echo "<tr class='tab_bg_1'><td><label for='host'>" . __('Server') . "</label></td>";
378
 echo "<td><input type='text' id='host' name='host' value='" . $this->fields["host"] . "'></td>";
379
 echo "<td><label for='port'>" . __('Port (default=389)') . "</label></td>";
380
 echo "<td><input id='port' type='text' id='port' name='port' value='".$this->fields["port"]."'>";
381
 echo "</td></tr>";
382
383
 echo "<tr class='tab_bg_1'><td><label for='condition'>" . __('Connection filter') . "</label></td>";
384
 echo "<td colspan='3'>";
385
 echo "<textarea cols='100' rows='1' id='condition' name='condition'>".$this->fields["condition"];
386
 echo "</textarea>";
387
 echo "</td></tr>";
388
389
 echo "<tr class='tab_bg_1'><td><label for='basedn'>" . __('BaseDN') . "</label></td>";
390
 echo "<td colspan='3'>";
391
 echo "<input type='text' id='basedn' name='basedn' size='100' value=\"".$this->fields["basedn"]."\">";
392
 echo "</td></tr>";
393
394
 echo "<tr class='tab_bg_1'><td><label for='rootdn'>" . __('RootDN (for non anonymous binds)') . "</label></td>";
395
 echo "<td colspan='3'><input type='text' name='rootdn' id='rootdn' size='100' value=\"".
396
 $this->fields["rootdn"]."\">";
397
 echo "</td></tr>";
398
399
 echo "<tr class='tab_bg_1'><td><label for='rootdn_passwd'>" .
400
 __('Password (for non-anonymous binds)') . "</label></td>";
401
 echo "<td><input type='password' id='rootdn_passwd' name='rootdn_passwd' value='' autocomplete='new-password'>";
402
 if ($ID) {
403
 echo "<input type='checkbox' name='_blank_passwd' id='_blank_passwd'>&nbsp;"
404
 . "<label for='_blank_passwd'>" . __('Clear') . "</label>";
405
 }
406
 echo "</td>";
407
 echo "<td rowspan='3'><label for='comment'>".__('Comments')."</label></td>";
408
 echo "<td rowspan='3' class='middle'>";
409
 echo "<textarea cols='40' rows='4' name='comment' id='comment'>".$this->fields["comment"]."</textarea>";
410
 echo "</td></tr>";
411
412
 echo "<tr class='tab_bg_1'>";
413
 echo "<td><label for='login_field'>" . __('Login field') . "</label></td>";
414
 echo "<td><input type='text' id='login_field' name='login_field' value='".$this->fields["login_field"]."'>";
415
 echo "</td></tr>";
416
417
 $info_message = __s('Synchronization field cannot be changed once in use.');
418
 echo "<tr class='tab_bg_1'>";
419
 echo "<td><label for='sync_field'>" . __('Synchronization field') . "<i class='pointer fa fa-info' title='$info_message'></i></td>";
420
 echo "<td><input type='text' id='sync_field' name='sync_field' value='{$this->fields["sync_field"]}' title='$info_message'";
421
 if ($this->isSyncFieldEnabled() && $this->isSyncFieldUsed()) {
422
 echo " disabled='disabled'";
423
 }
424
 echo ">";
425
 echo "</td></tr>";
426
427
 //Fill fields when using preconfiguration models
428
 if (!$ID) {
429
 $hidden_fields = ['comment_field', 'email1_field', 'email2_field',
430
 'email3_field', 'email4_field', 'entity_condition',
431
 'entity_field', 'firstname_field', 'group_condition',
432
 'group_field', 'group_member_field', 'group_search_type',
433
 'mobile_field', 'phone_field', 'phone2_field',
434
 'realname_field', 'registration_number_field', 'title_field',
435
 'use_dn', 'use_tls', 'responsible_field'];
436
437
 foreach ($hidden_fields as $hidden_field) {
438
 echo "<input type='hidden' name='$hidden_field' value='".
439
 $this->fields[$hidden_field]."'>";
440
 }
441
 }
442
443
 echo "</td></tr>";
444
445
 $this->showFormButtons($options);
446
447
 } else {
448
 echo "<div class='center'>&nbsp;<table class='tab_cadre_fixe'>";
449
 echo "<tr><th colspan='2'>" . self::getTypeName(1) . "</th></tr>";
450
 echo "<tr class='tab_bg_2'><td class='center'>";
451
 echo "<p class='red'>".sprintf(__('%s extension is missing'), 'LDAP')."</p>";
452
 echo "<p>".__('Impossible to use LDAP as external source of connection')."</p>".
453
 "</td></tr></table>";
454
455
 echo "<p><strong>".GLPINetwork::getSupportPromoteMessage()."</strong></p>";
456
 echo "</div>";
457
458
 }
459
 }
460
461
 /**
462
 * Show advanced config form
463
 *
464
 * @return void
465
 */
466
 function showFormAdvancedConfig() {
467
468
 $ID = $this->getField('id');
469
 $hidden = '';
470
471
 echo "<div class='center'>";
472
 echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
473
 echo "<table class='tab_cadre_fixe'>";
474
475
 echo "<tr class='tab_bg_2'><th colspan='4'>";
476
 echo "<input type='hidden' name='id' value='$ID'>". __('Advanced information')."</th></tr>";
477
478
 echo "<tr class='tab_bg_1'>";
479
 echo "<td>" . __('Use TLS') . "</td><td>";
480
 if (function_exists("ldap_start_tls")) {
481
 Dropdown::showYesNo('use_tls', $this->fields["use_tls"]);
482
 } else {
483
 echo "<input type='hidden' name='use_tls' value='0'>".__('ldap_start_tls does not exist');
484
 }
485
 echo "</td>";
486
 echo "<td>" . __('LDAP directory time zone') . "</td><td>";
487
 Dropdown::showGMT("time_offset", $this->fields["time_offset"]);
488
 echo"</td></tr>";
489
490
 if (self::isLdapPageSizeAvailable(false, false)) {
491
 echo "<tr class='tab_bg_1'>";
492
 echo "<td>" . __('Use paged results') . "</td><td>";
493
 Dropdown::showYesNo('can_support_pagesize', $this->fields["can_support_pagesize"]);
494
 echo "</td>";
495
 echo "<td>" . __('Page size') . "</td><td>";
496
 Dropdown::showNumber("pagesize", ['value' => $this->fields['pagesize'],
497
 'min' => 100,
498
 'max' => 100000,
499
 'step' => 100]);
500
 echo"</td></tr>";
501
502
 echo "<tr class='tab_bg_1'>";
503
 echo "<td>" . __('Maximum number of results') . "</td><td>";
504
 Dropdown::showNumber('ldap_maxlimit', ['value' => $this->fields['ldap_maxlimit'],
505
 'min' => 100,
506
 'max' => 999999,
507
 'step' => 100,
508
 'toadd' => [0 => __('Unlimited')]]);
509
 echo "</td><td colspan='2'></td></tr>";
510
511
 } else {
512
 $hidden .= "<input type='hidden' name='can_support_pagesize' value='0'>";
513
 $hidden .= "<input type='hidden' name='pagesize' value='0'>";
514
 $hidden .= "<input type='hidden' name='ldap_maxlimit' value='0'>";
515
 }
516
517
 echo "<tr class='tab_bg_1'>";
518
 echo "<td>" . __('How LDAP aliases should be handled') . "</td><td colspan='4'>";
519
 $alias_options = [
520
 LDAP_DEREF_NEVER => __('Never dereferenced (default)'),
521
 LDAP_DEREF_ALWAYS => __('Always dereferenced'),
522
 LDAP_DEREF_SEARCHING => __('Dereferenced during the search (but not when locating)'),
523
 LDAP_DEREF_FINDING => __('Dereferenced when locating (not during the search)'),
524
 ];
525
 Dropdown::showFromArray("deref_option", $alias_options,
526
 ['value' => $this->fields["deref_option"]]);
527
 echo"</td></tr>";
528
529
 echo "<tr class='tab_bg_1'>";
530
 echo "<td>".__('Domain name used by inventory tool for link the user')."</td>";
531
 echo "<td colspan='3'>";
532
 Html::autocompletionTextField($this, "inventory_domain", ['size' => 100]);
533
 echo "</td></tr>";
534
535
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
536
 echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
537
 echo $hidden;
538
 echo "</td></tr>";
539
540
 echo "</table>";
541
 Html::closeForm();
542
 echo "</div>";
543
544
 }
545
546
 /**
547
 * Show config replicates form
548
 *
549
 * @var DBmysql $DB
550
 *
551
 * @return void
552
 */
553
 function showFormReplicatesConfig() {
554
 global $DB;
555
556
 $ID = $this->getField('id');
557
 $target = $this->getFormURL();
558
 $rand = mt_rand();
559
560
 AuthLdapReplicate::addNewReplicateForm($target, $ID);
561
562
 $iterator = $DB->request([
563
 'FROM' => 'glpi_authldapreplicates',
564
 'WHERE' => [
565
 'authldaps_id' => $ID
566
 ],
567
 'ORDER' => ['name']
568
 ]);
569
570
 if (($nb = count($iterator)) > 0) {
571
 echo "<br>";
572
573
 echo "<div class='center'>";
574
 Html::openMassiveActionsForm('massAuthLdapReplicate'.$rand);
575
 $massiveactionparams = ['num_displayed' => min($_SESSION['glpilist_limit'], $nb),
576
 'container' => 'massAuthLdapReplicate'.$rand];
577
 Html::showMassiveActions($massiveactionparams);
578
 echo "<input type='hidden' name='id' value='$ID'>";
579
 echo "<table class='tab_cadre_fixehov'>";
580
 echo "<tr class='noHover'>".
581
 "<th colspan='4'>".__('List of LDAP directory replicates') . "</th></tr>";
582
583
 if (isset($_SESSION["LDAP_TEST_MESSAGE"])) {
584
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
585
 echo $_SESSION["LDAP_TEST_MESSAGE"];
586
 echo"</td></tr>";
587
 unset($_SESSION["LDAP_TEST_MESSAGE"]);
588
 }
589
 $header_begin = "<tr>";
590
 $header_top = "<th>".Html::getCheckAllAsCheckbox('massAuthLdapReplicate'.$rand)."</th>";
591
 $header_bottom = "<th>".Html::getCheckAllAsCheckbox('massAuthLdapReplicate'.$rand)."</th>";
592
 $header_end = "<th class='center b'>".__('Name')."</th>";
593
 $header_end .= "<th class='center b'>"._n('Replicate', 'Replicates', 1)."</th>".
594
 "<th class='center'></th></tr>";
595
 echo $header_begin.$header_top.$header_end;
596
597
 while ($ldap_replicate = $iterator->next()) {
598
 echo "<tr class='tab_bg_1'><td class='center' width='10'>";
599
 Html::showMassiveActionCheckBox('AuthLdapReplicate', $ldap_replicate["id"]);
600
 echo "</td>";
601
 echo "<td class='center'>" . $ldap_replicate["name"] . "</td>";
602
 echo "<td class='center'>".sprintf(__('%1$s: %2$s'), $ldap_replicate["host"],
603
 $ldap_replicate["port"]);
604
 echo "</td>";
605
 echo "<td class='center'>";
606
 Html::showSimpleForm(static::getFormURL(),
607
 'test_ldap_replicate', _sx('button', 'Test'),
608
 ['id' => $ID,
609
 'ldap_replicate_id' => $ldap_replicate["id"]]);
610
 echo "</td></tr>";
611
 }
612
 echo $header_begin.$header_bottom.$header_end;
613
 echo "</table>";
614
 $massiveactionparams['ontop'] = false;
615
 Html::showMassiveActions($massiveactionparams);
616
617
 Html::closeForm();
618
 echo "</div>";
619
 }
620
 }
621
622
 /**
623
 * Build a dropdown
624
 *
625
 * @since 0.84
626
 *
627
 * @param array $options Options
628
 *
629
 * @return string
630
 */
631
 static function dropdownGroupSearchType(array $options) {
632
633
 $p = [
634
 'name' => 'group_search_type',
635
 'value' => self::GROUP_SEARCH_USER,
636
 'display' => true,
637
 ];
638
639
 if (count($options)) {
640
 foreach ($options as $key => $val) {
641
 $p[$key] = $val;
642
 }
643
 }
644
645
 $tab = self::getGroupSearchTypeName();
646
 return Dropdown::showFromArray($p['name'], $tab, $p);
647
 }
648
649
 /**
650
 * Get the possible value for contract alert
651
 *
652
 * @since 0.83
653
 *
654
 * @param integer $val if not set, ask for all values, else for 1 value (default NULL)
655
 *
656
 * @return array|string
657
 */
658
 static function getGroupSearchTypeName($val = null) {
659
 $tmp = [
660
 self::GROUP_SEARCH_USER => __('In users'),
661
 self::GROUP_SEARCH_GROUP => __('In groups'),
662
 self::GROUP_SEARCH_BOTH => __('In users and groups')
663
 ];
664
665
 if (is_null($val)) {
666
 return $tmp;
667
 }
668
 if (isset($tmp[$val])) {
669
 return $tmp[$val];
670
 }
671
 return NOT_AVAILABLE;
672
 }
673
674
 /**
675
 * Show group config form
676
 *
677
 * @return void
678
 */
679
 function showFormGroupsConfig() {
680
681
 $ID = $this->getField('id');
682
683
 echo "<div class='center'>";
684
 echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
685
 echo "<input type='hidden' name='id' value='$ID'>";
686
 echo "<table class='tab_cadre_fixe'>";
687
688
 echo "<tr><th class='center' colspan='4'>" . __('Belonging to groups') . "</th></tr>";
689
690
 echo "<tr class='tab_bg_1'><td>" . __('Search type') . "</td><td>";
691
 self::dropdownGroupSearchType(['value' => $this->fields["group_search_type"]]);
692
 echo "</td>";
693
 echo "<td>" . __('User attribute containing its groups') . "</td>";
694
 echo "<td><input type='text' name='group_field' value='".$this->fields["group_field"]."'>";
695
 echo "</td></tr>";
696
697
 echo "<tr class='tab_bg_1'><td>" . __('Filter to search in groups')."</td><td colspan='3'>";
698
 echo "<textarea cols='100' rows='1' name='group_condition'>".$this->fields["group_condition"];
699
 echo "</textarea>";
700
 echo "</td></tr>";
701
702
 echo "<tr class='tab_bg_1'><td>" . __('Group attribute containing its users') . "</td>";
703
 echo "<td><input type='text' name='group_member_field' value='".
704
 $this->fields["group_member_field"]."'></td>";
705
 echo "<td>" . __('Use DN in the search') . "</td>";
706
 echo "<td>";
707
 Dropdown::showYesNo("use_dn", $this->fields["use_dn"]);
708
 echo "</td></tr>";
709
710
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
711
 echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
712
 echo "</td></tr>";
713
 echo "</table>";
714
 Html::closeForm();
715
 echo "</div>";
716
 }
717
718
 /**
719
 * Show ldap test form
720
 *
721
 * @return void
722
 */
723
 function showFormTestLDAP () {
724
725
 $ID = $this->getField('id');
726
727
 if ($ID > 0) {
728
 echo "<div class='center'>";
729
 echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
730
 echo "<input type='hidden' name='id' value='$ID'>";
731
 echo "<table class='tab_cadre_fixe'>";
732
 echo "<tr><th colspan='4'>" . __('Test of connection to LDAP directory') . "</th></tr>";
733
734
 if (isset($_SESSION["LDAP_TEST_MESSAGE"])) {
735
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
736
 echo $_SESSION["LDAP_TEST_MESSAGE"];
737
 echo"</td></tr>";
738
 unset($_SESSION["LDAP_TEST_MESSAGE"]);
739
 }
740
741
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
742
 echo "<input type='submit' name='test_ldap' class='submit' value=\"".
743
 _sx('button', 'Test')."\">";
744
 echo "</td></tr>";
745
 echo "</table>";
746
 Html::closeForm();
747
 echo "</div>";
748
 }
749
 }
750
751
 /**
752
 * Show user config form
753
 *
754
 * @return void
755
 */
756
 function showFormUserConfig() {
757
758
 $ID = $this->getField('id');
759
760
 echo "<div class='center'>";
761
 echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
762
 echo "<input type='hidden' name='id' value='$ID'>";
763
 echo "<table class='tab_cadre_fixe'>";
764
765
 echo "<tr class='tab_bg_1'>";
766
 echo "<th class='center' colspan='4'>" . __('Binding to the LDAP directory') . "</th></tr>";
767
768
 echo "<tr class='tab_bg_2'><td>" . __('Surname') . "</td>";
769
 echo "<td><input type='text' name='realname_field' value='".
770
 $this->fields["realname_field"]."'></td>";
771
 echo "<td>" . __('First name') . "</td>";
772
 echo "<td><input type='text' name='firstname_field' value='".
773
 $this->fields["firstname_field"]."'></td></tr>";
774
775
 echo "<tr class='tab_bg_2'><td>" . __('Comments') . "</td>";
776
 echo "<td><input type='text' name='comment_field' value='".$this->fields["comment_field"]."'>";
777
 echo "</td>";
778
 echo "<td>" . __('Administrative number') . "</td>";
779
 echo "<td>";
780
 echo "<input type='text' name='registration_number_field' value='".
781
 $this->fields["registration_number_field"]."'>";
782
 echo "</td></tr>";
783
784
 echo "<tr class='tab_bg_2'>";
785
 echo "<td>" . _n('Email', 'Emails', 1) . "</td>";
786
 echo "<td><input type='text' name='email1_field' value='".$this->fields["email1_field"]."'>";
787
 echo "</td>";
788
 echo "<td>" . sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '2') . "</td>";
789
 echo "<td><input type='text' name='email2_field' value='".$this->fields["email2_field"]."'>";
790
 echo "</td></tr>";
791
792
 echo "<tr class='tab_bg_2'>";
793
 echo "<td>" . sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '3') . "</td>";
794
 echo "<td><input type='text' name='email3_field' value='".$this->fields["email3_field"]."'>";
795
 echo "</td>";
796
 echo "<td>" . sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '4') . "</td>";
797
 echo "<td><input type='text' name='email4_field' value='".$this->fields["email4_field"]."'>";
798
 echo "</td></tr>";
799
800
 echo "<tr class='tab_bg_2'><td>" . _x('ldap', 'Phone') . "</td>";
801
 echo "<td><input type='text' name='phone_field'value='".$this->fields["phone_field"]."'>";
802
 echo "</td>";
803
 echo "<td>" . __('Phone 2') . "</td>";
804
 echo "<td><input type='text' name='phone2_field'value='".$this->fields["phone2_field"]."'>";
805
 echo "</td></tr>";
806
807
 echo "<tr class='tab_bg_2'><td>" . __('Mobile phone') . "</td>";
808
 echo "<td><input type='text' name='mobile_field'value='".$this->fields["mobile_field"]."'>";
809
 echo "</td>";
810
 echo "<td>" . _x('person', 'Title') . "</td>";
811
 echo "<td><input type='text' name='title_field' value='".$this->fields["title_field"]."'>";
812
 echo "</td></tr>";
813
814
 echo "<tr class='tab_bg_2'><td>" . __('Category') . "</td>";
815
 echo "<td><input type='text' name='category_field' value='".
816
 $this->fields["category_field"]."'></td>";
817
 echo "<td>" . __('Language') . "</td>";
818
 echo "<td><input type='text' name='language_field' value='".
819
 $this->fields["language_field"]."'></td></tr>";
820
821
 echo "<tr class='tab_bg_2'><td>" . __('Picture') . "</td>";
822
 echo "<td><input type='text' name='picture_field' value='".
823
 $this->fields["picture_field"]."'></td>";
824
 echo "<td>" . Location::getTypeName(1) . "</td>";
825
 echo "<td><input type='text' name='location_field' value='".$this->fields["location_field"]."'>";
826
 echo "</td></tr>";
827
828
 echo "<tr class='tab_bg_2'><td>" . __('Responsible') . "</td>";
829
 echo "<td><input type='text' name='responsible_field' value='".
830
 $this->fields["responsible_field"]."'></td>";
831
 echo "<td colspan='2'></td></tr>";
832
833
 echo "<tr><td colspan=4 class='center green'>".__('You can use a field name or an expression using various %{fieldname}').
834
 " <br />".__('Example for location: %{city} > %{roomnumber}')."</td></tr>";
835
836
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
837
 echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
838
 echo "</td></tr>";
839
 echo "</table>";
840
 Html::closeForm();
841
 echo "</div>";
842
 }
843
844
 /**
845
 * Show entity config form
846
 *
847
 * @return void
848
 */
849
 function showFormEntityConfig() {
850
851
 $ID = $this->getField('id');
852
853
 echo "<div class='center'>";
854
 echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
855
 echo "<input type='hidden' name='id' value='$ID'>";
856
 echo "<table class='tab_cadre_fixe'>";
857
858
 echo "<tr><th class='center' colspan='4'>". __('Import entities from LDAP directory').
859
 "</th></tr>";
860
861
 echo "<tr class='tab_bg_1'><td>" . __('Attribute representing entity') . "</td>";
862
 echo "<td colspan='3'>";
863
 echo "<input type='text' name='entity_field' value='".$this->fields["entity_field"]."'>";
864
 echo "</td></tr>";
865
866
 echo "<tr class='tab_bg_1'><td>" . __('Search filter for entities') . "</td>";
867
 echo "<td colspan='3'>";
868
 echo "<input type='text' name='entity_condition' value='".$this->fields["entity_condition"]."'
869
 size='100'></td></tr>";
870
871
 echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
872
 echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
873
 echo "</td></tr>";
874
 echo "</table>";
875
 Html::closeForm();
876
 echo "</div>";
877
 }
878
879
 function defineTabs($options = []) {
880
881
 $ong = [];
882
 $this->addDefaultFormTab($ong);
883
 $this->addStandardTab(__CLASS__, $ong, $options);
884
 $this->addImpactTab($ong, $options);
885
 $this->addStandardTab('Log', $ong, $options);
886
887
 return $ong;
888
 }
889
890
 function rawSearchOptions() {
891
 $tab = [];
892
893
 $tab[] = [
894
 'id' => 'common',
895
 'name' => $this->getTypeName(1)
896
 ];
897
898
 $tab[] = [
899
 'id' => '1',
900
 'table' => $this->getTable(),
901
 'field' => 'name',
902
 'name' => __('Name'),
903
 'datatype' => 'itemlink',
904
 'massiveaction' => false
905
 ];
906
907
 $tab[] = [
908
 'id' => '2',
909
 'table' => $this->getTable(),
910
 'field' => 'id',
911
 'name' => __('ID'),
912
 'datatype' => 'number',
913
 'massiveaction' => false
914
 ];
915
916
 $tab[] = [
917
 'id' => '3',
918
 'table' => $this->getTable(),
919
 'field' => 'host',
920
 'name' => __('Server'),
921
 'datatype' => 'string'
922
 ];
923
924
 $tab[] = [
925
 'id' => '4',
926
 'table' => $this->getTable(),
927
 'field' => 'port',
928
 'name' => _n('Port', 'Ports', 1),
929
 'datatype' => 'integer'
930
 ];
931
932
 $tab[] = [
933
 'id' => '5',
934
 'table' => $this->getTable(),
935
 'field' => 'basedn',
936
 'name' => __('BaseDN'),
937
 'datatype' => 'string'
938
 ];
939
940
 $tab[] = [
941
 'id' => '6',
942
 'table' => $this->getTable(),
943
 'field' => 'condition',
944
 'name' => __('Connection filter'),
945
 'datatype' => 'text'
946
 ];
947
948
 $tab[] = [
949
 'id' => '7',
950
 'table' => $this->getTable(),
951
 'field' => 'is_default',
952
 'name' => __('Default server'),
953
 'datatype' => 'bool',
954
 'massiveaction' => false
955
 ];
956
957
 $tab[] = [
958
 'id' => '8',
959
 'table' => $this->getTable(),
960
 'field' => 'login_field',
961
 'name' => __('Login field'),
962
 'massiveaction' => false,
963
 'datatype' => 'string'
964
 ];
965
966
 $tab[] = [
967
 'id' => '9',
968
 'table' => $this->getTable(),
969
 'field' => 'realname_field',
970
 'name' => __('Surname'),
971
 'massiveaction' => false,
972
 'datatype' => 'string'
973
 ];
974
975
 $tab[] = [
976
 'id' => '10',
977
 'table' => $this->getTable(),
978
 'field' => 'firstname_field',
979
 'name' => __('First name'),
980
 'massiveaction' => false,
981
 'datatype' => 'string'
982
 ];
983
984
 $tab[] = [
985
 'id' => '11',
986
 'table' => $this->getTable(),
987
 'field' => 'phone_field',
988
 'name' => _x('ldap', 'Phone'),
989
 'massiveaction' => false,
990
 'datatype' => 'string'
991
 ];
992
993
 $tab[] = [
994
 'id' => '12',
995
 'table' => $this->getTable(),
996
 'field' => 'phone2_field',
997
 'name' => __('Phone 2'),
998
 'massiveaction' => false,
999
 'datatype' => 'string'
1000
 ];
1001
1002
 $tab[] = [
1003
 'id' => '13',
1004
 'table' => $this->getTable(),
1005
 'field' => 'mobile_field',
1006
 'name' => __('Mobile phone'),
1007
 'massiveaction' => false,
1008
 'datatype' => 'string'
1009
 ];
1010
1011
 $tab[] = [
1012
 'id' => '14',
1013
 'table' => $this->getTable(),
1014
 'field' => 'title_field',
1015
 'name' => _x('person', 'Title'),
1016
 'massiveaction' => false,
1017
 'datatype' => 'string'
1018
 ];
1019
1020
 $tab[] = [
1021
 'id' => '15',
1022
 'table' => $this->getTable(),
1023
 'field' => 'category_field',
1024
 'name' => __('Category'),
1025
 'massiveaction' => false,
1026
 'datatype' => 'string'
1027
 ];
1028
1029
 $tab[] = [
1030
 'id' => '16',
1031
 'table' => $this->getTable(),
1032
 'field' => 'comment',
1033
 'name' => __('Comments'),
1034
 'datatype' => 'text'
1035
 ];
1036
1037
 $tab[] = [
1038
 'id' => '17',
1039
 'table' => $this->getTable(),
1040
 'field' => 'email1_field',
1041
 'name' => _n('Email', 'Emails', 1),
1042
 'massiveaction' => false,
1043
 'datatype' => 'string'
1044
 ];
1045
1046
 $tab[] = [
1047
 'id' => '25',
1048
 'table' => $this->getTable(),
1049
 'field' => 'email2_field',
1050
 'name' => sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '2'),
1051
 'massiveaction' => false,
1052
 'datatype' => 'string'
1053
 ];
1054
1055
 $tab[] = [
1056
 'id' => '26',
1057
 'table' => $this->getTable(),
1058
 'field' => 'email3_field',
1059
 'name' => sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '3'),
1060
 'massiveaction' => false,
1061
 'datatype' => 'string'
1062
 ];
1063
1064
 $tab[] = [
1065
 'id' => '27',
1066
 'table' => $this->getTable(),
1067
 'field' => 'email4_field',
1068
 'name' => sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '4'),
1069
 'massiveaction' => false,
1070
 'datatype' => 'string'
1071
 ];
1072
1073
 $tab[] = [
1074
 'id' => '18',
1075
 'table' => $this->getTable(),
1076
 'field' => 'use_dn',
1077
 'name' => __('Use DN in the search'),
1078
 'datatype' => 'bool',
1079
 'massiveaction' => false
1080
 ];
1081
1082
 $tab[] = [
1083
 'id' => '19',
1084
 'table' => $this->getTable(),
1085
 'field' => 'date_mod',
1086
 'name' => __('Last update'),
1087
 'datatype' => 'datetime',
1088
 'massiveaction' => false
1089
 ];
1090
1091
 $tab[] = [
1092
 'id' => '121',
1093
 'table' => $this->getTable(),
1094
 'field' => 'date_creation',
1095
 'name' => __('Creation date'),
1096
 'datatype' => 'datetime',
1097
 'massiveaction' => false
1098
 ];
1099
1100
 $tab[] = [
1101
 'id' => '20',
1102
 'table' => $this->getTable(),
1103
 'field' => 'language_field',
1104
 'name' => __('Language'),
1105
 'massiveaction' => false,
1106
 'datatype' => 'string'
1107
 ];
1108
1109
 $tab[] = [
1110
 'id' => '21',
1111
 'table' => $this->getTable(),
1112
 'field' => 'group_field',
1113
 'name' => __('User attribute containing its groups'),
1114
 'massiveaction' => false,
1115
 'datatype' => 'string'
1116
 ];
1117
1118
 $tab[] = [
1119
 'id' => '22',
1120
 'table' => $this->getTable(),
1121
 'field' => 'group_condition',
1122
 'name' => __('Filter to search in groups'),
1123
 'massiveaction' => false,
1124
 'datatype' => 'text'
1125
 ];
1126
1127
 $tab[] = [
1128
 'id' => '23',
1129
 'table' => $this->getTable(),
1130
 'field' => 'group_member_field',
1131
 'name' => __('Group attribute containing its users'),
1132
 'massiveaction' => false,
1133
 'datatype' => 'string'
1134
 ];
1135
1136
 $tab[] = [
1137
 'id' => '24',
1138
 'table' => $this->getTable(),
1139
 'field' => 'group_search_type',
1140
 'datatype' => 'specific',
1141
 'name' => __('Search type'),
1142
 'massiveaction' => false
1143
 ];
1144
1145
 $tab[] = [
1146
 'id' => '30',
1147
 'table' => $this->getTable(),
1148
 'field' => 'is_active',
1149
 'name' => __('Active'),
1150
 'datatype' => 'bool'
1151
 ];
1152
1153
 $tab[] = [
1154
 'id' => '28',
1155
 'table' => $this->getTable(),
1156
 'field' => 'sync_field',
1157
 'name' => __('Synchronization field'),
1158
 'massiveaction' => false,
1159
 'datatype' => 'string'
1160
 ];
1161
1162
 $tab[] = [
1163
 'id' => '29',
1164
 'table' => $this->getTable(),
1165
 'field' => 'responsible_field',
1166
 'name' => __('Responsible'),
1167
 'massiveaction' => false,
1168
 'datatype' => 'string'
1169
 ];
1170
1171
 $tab[] = [
1172
 'id' => '31',
1173
 'table' => $this->getTable(),
1174
 'field' => 'inventory_domain',
1175
 'name' => __('Domain name used by inventory tool'),
1176
 'massiveaction' => false,
1177
 'datatype' => 'string',
1178
 'autocomplete' => true,
1179
 ];
1180
1181
 return $tab;
1182
 }
1183
1184
 /**
1185
 * Show system informations form
1186
 *
1187
 * @param integer $width The number of characters at which the string will be wrapped.
1188
 *
1189
 * @return void
1190
 */
1191
 function showSystemInformations($width) {
1192
1193
 // No need to translate, this part always display in english (for copy/paste to forum)
1194
1195
 $ldap_servers = self::getLdapServers();
1196
1197
 if (!empty($ldap_servers)) {
1198
 echo "<tr class='tab_bg_2'><th>" . self::getTypeName(Session::getPluralNumber()) . "</th></tr>\n";
1199
 echo "<tr class='tab_bg_1'><td><pre>\n&nbsp;\n";
1200
 foreach ($ldap_servers as $value) {
1201
 $fields = ['Server' => 'host',
1202
 'Port' => 'port',
1203
 'BaseDN' => 'basedn',
1204
 'Connection filter' => 'condition',
1205
 'RootDN' => 'rootdn',
1206
 'Use TLS' => 'use_tls'];
1207
 $msg = '';
1208
 $first = true;
1209
 foreach ($fields as $label => $field) {
1210
 $msg .= (!$first ? ', ' : '').
1211
 $label.': '.
1212
 ($value[$field]? '\''.$value[$field].'\'' : 'none');
1213
 $first = false;
1214
 }
1215
 echo wordwrap($msg."\n", $width, "\n\t\t");
1216
 }
1217
 echo "\n</pre></td></tr>";
1218
 }
1219
 }
1220
1221
1222
 /**
1223
 * Get LDAP fields to sync to GLPI data from a glpi_authldaps array
1224
 *
1225
 * @param array $authtype_array Authentication method config array (from table)
1226
 *
1227
 * @return array of "user table field name" => "config value"
1228
 */
1229
 static function getSyncFields(array $authtype_array) {
1230
1231
 $ret = [];
1232
 $fields = ['login_field' => 'name',
1233
 'email1_field' => 'email1',
1234
 'email2_field' => 'email2',
1235
 'email3_field' => 'email3',
1236
 'email4_field' => 'email4',
1237
 'realname_field' => 'realname',
1238
 'firstname_field' => 'firstname',
1239
 'phone_field' => 'phone',
1240
 'phone2_field' => 'phone2',
1241
 'mobile_field' => 'mobile',
1242
 'location_field' => 'locations_id',
1243
 'comment_field' => 'comment',
1244
 'title_field' => 'usertitles_id',
1245
 'category_field' => 'usercategories_id',
1246
 'language_field' => 'language',
1247
 'registration_number_field' => 'registration_number',
1248
 'picture_field' => 'picture',
1249
 'responsible_field' => 'users_id_supervisor',
1250
 'sync_field' => 'sync_field'];
1251
1252
 foreach ($fields as $key => $val) {
1253
 if (isset($authtype_array[$key]) && !empty($authtype_array[$key])) {
1254
 $ret[$val] = $authtype_array[$key];
1255
 }
1256
 }
1257
 return $ret;
1258
 }
1259
1260
1261
 /**
1262
 * Display LDAP filter
1263
 *
1264
 * @param string $target target for the form
1265
 * @param boolean $users for user? (true by default)
1266
 *
1267
 * @return void
1268
 */
1269
 static function displayLdapFilter($target, $users = true) {
1270
1271
 $config_ldap = new self();
1272
 if (!isset($_SESSION['ldap_server'])) {
1273
 throw new \RuntimeException('LDAP server must be set!');
1274
 }
1275
 $config_ldap->getFromDB($_SESSION['ldap_server']);
1276
1277
 if ($users) {
1278
 $filter_name1 = "condition";
1279
 $filter_var = "ldap_filter";
1280
1281
 } else {
1282
 $filter_var = "ldap_group_filter";
1283
 switch ($config_ldap->fields["group_search_type"]) {
1284
 case self::GROUP_SEARCH_USER:
1285
 $filter_name1 = "condition";
1286
 break;
1287
1288
 case self::GROUP_SEARCH_GROUP:
1289
 $filter_name1 = "group_condition";
1290
 break;
1291
1292
 case self::GROUP_SEARCH_BOTH:
1293
 $filter_name1 = "group_condition";
1294
 $filter_name2 = "condition";
1295
 break;
1296
 }
1297
 }
1298
1299
 if (!isset($_SESSION[$filter_var]) || ($_SESSION[$filter_var] == '')) {
1300
 $_SESSION[$filter_var] = $config_ldap->fields[$filter_name1];
1301
 }
1302
1303
 echo "<div class='center'>";
1304
 echo "<form method='post' action='$target'>";
1305
 echo "<table class='tab_cadre_fixe'>";
1306
 echo "<tr><th colspan='2'>" . ($users?__('Search filter for users')
1307
 :__('Filter to search in groups')) . "</th></tr>";
1308
1309
 echo "<tr class='tab_bg_2'><td class='center'>";
1310
 echo "<input type='text' name='ldap_filter' value='". $_SESSION[$filter_var] ."' size='70'>";
1311
 //Only display when looking for groups in users AND groups
1312
 if (!$users
1313
 && ($config_ldap->fields["group_search_type"] == self::GROUP_SEARCH_BOTH)) {
1314
1315
 if (!isset($_SESSION["ldap_group_filter2"]) || ($_SESSION["ldap_group_filter2"] == '')) {
1316
 $_SESSION["ldap_group_filter2"] = $config_ldap->fields[$filter_name2];
1317
 }
1318
 echo "</td></tr>";
1319
1320
 echo "<tr><th colspan='2'>" . __('Search filter for users') . "</th></tr>";
1321
1322
 echo "<tr class='tab_bg_2'><td class='center'>";
1323
 echo "<input type='text' name='ldap_filter2' value='".$_SESSION["ldap_group_filter2"]."'
1324
 size='70'></td></tr>";
1325
 }
1326
1327
 echo "<tr class='tab_bg_2'><td class='center'>";
1328
 echo "<input class=submit type='submit' name='change_ldap_filter' value=\"".
1329
 _sx('button', 'Post')."\"></td></tr>";
1330
 echo "</table>";
1331
 Html::closeForm();
1332
 echo "</div>";
1333
 }
1334
1335
1336
 /**
1337
 * Converts LDAP timestamps over to Unix timestamps
1338
 *
1339
 * @param string $ldapstamp LDAP timestamp
1340
 * @param integer $ldap_time_offset time offset (default 0)
1341
 *
1342
 * @return integer unix timestamp
1343
 */
1344
 static function ldapStamp2UnixStamp($ldapstamp, $ldap_time_offset = 0) {
1345
 global $CFG_GLPI;
1346
1347
 //Check if timestamp is well format, otherwise return ''
1348
 if (!preg_match("/[\d]{14}(\.[\d]{0,4})*Z/", $ldapstamp)) {
1349
 return '';
1350
 }
1351
1352
 $year = substr($ldapstamp, 0, 4);
1353
 $month = substr($ldapstamp, 4, 2);
1354
 $day = substr($ldapstamp, 6, 2);
1355
 $hour = substr($ldapstamp, 8, 2);
1356
 $minute = substr($ldapstamp, 10, 2);
1357
 $seconds = substr($ldapstamp, 12, 2);
1358
 $stamp = gmmktime($hour, $minute, $seconds, $month, $day, $year);
1359
 $stamp += $CFG_GLPI["time_offset"]-$ldap_time_offset;
1360
1361
 return $stamp;
1362
 }
1363
1364
1365
 /**
1366
 * Converts a Unix timestamp to an LDAP timestamps
1367
 *
1368
 * @param string $date datetime
1369
 *
1370
 * @return string ldap timestamp
1371
 */
1372
 static function date2ldapTimeStamp($date) {
1373
 return date("YmdHis", strtotime($date)).'.0Z';
1374
 }
1375
1376
1377
 /**
1378
 * Return the LDAP field to use for user synchronization
1379
 * It may be sync_field if defined, or login_field
1380
 * @since 9.2
1381
 *
1382
 * @return string the ldap field to use for user synchronization
1383
 */
1384
 public function getLdapIdentifierToUse() {
1385
 if (!empty($this->fields['sync_field'])) {
1386
 return $this->fields['sync_field'];
1387
 } else {
1388
 return $this->fields['login_field'];
1389
 }
1390
 }
1391
1392
 /**
1393
 * Return the database field to use for user synchronization
1394
 * @since 9.2
1395
 *
1396
 * @return string the database field to use for user synchronization
1397
 */
1398
 public function getDatabaseIdentifierToUse() {
1399
 if (!empty($this->fields['sync_field'])) {
1400
 return 'sync_field';
1401
 } else {
1402
 return 'name';
1403
 }
1404
 }
1405
1406
 /**
1407
 * Indicates if there's a sync_field enabled in the LDAP configuration
1408
 * @since 9.2
1409
 *
1410
 * @return boolean true if the sync_field is enabled (the field is filled)
1411
 */
1412
 public function isSyncFieldEnabled() {
1413
 return (!empty($this->fields['sync_field']));
1414
 }
1415
1416
 /**
1417
 * Check if the sync_field is configured for an LDAP server
1418
 *
1419
 * @since 9.2
1420
 * @param integer authldaps_id the LDAP server ID
1421
 * @return boolean true if configured, false if not configured
1422
 */
1423
 public static function isSyncFieldConfigured($authldaps_id) {
1424
 $authldap = new self();
1425
 $authldap->getFromDB($authldaps_id);
1426
 return ($authldap->isSyncFieldEnabled());
1427
 }
1428
1429
 /**
1430
 * Test a LDAP connection
1431
 *
1432
 * @param integer $auths_id ID of the LDAP server
1433
 * @param integer $replicate_id use a replicate if > 0 (default -1)
1434
 *
1435
 * @return boolean connection succeeded?
1436
 */
1437
 static function testLDAPConnection($auths_id, $replicate_id = -1) {
1438
1439
 $config_ldap = new self();
1440
 $res = $config_ldap->getFromDB($auths_id);
1441
1442
 // we prevent some delay...
1443
 if (!$res) {
1444
 return false;
1445
 }
1446
1447
 //Test connection to a replicate
1448
 if ($replicate_id != -1) {
1449
 $replicate = new AuthLdapReplicate();
1450
 $replicate->getFromDB($replicate_id);
1451
 $host = $replicate->fields["host"];
1452
 $port = $replicate->fields["port"];
1453
1454
 } else {
1455
 //Test connection to a master ldap server
1456
 $host = $config_ldap->fields['host'];
1457
 $port = $config_ldap->fields['port'];
1458
 }
1459
 $ds = self::connectToServer($host, $port, $config_ldap->fields['rootdn'],
1460
 Toolbox::sodiumDecrypt($config_ldap->fields['rootdn_passwd']),
1461
 $config_ldap->fields['use_tls'],
1462
 $config_ldap->fields['deref_option']);
1463
 if ($ds) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (1)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

$ds is of type resource, thus it always evaluated to false.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (2) Loading history...

1464
 return true;
1465
 }
1466
 return false;
1467
 }
1468
1469
1470
 /**
1471
 * Display a warnign about size limit
1472
 *
1473
 * @since 0.84
1474
 *
1475
 * @param boolean $limitexceeded (false by default)
1476
 *
1477
 * @return void
1478
 */
1479
 static function displaySizeLimitWarning($limitexceeded = false) {
1480
 global $CFG_GLPI;
1481
1482
 if ($limitexceeded) {
1483
 echo "<div class='firstbloc'><table class='tab_cadre_fixe'>";
1484
 echo "<tr><th class='red'>";
1485
 echo "<img class='center' src='".$CFG_GLPI["root_doc"]."/pics/warning.png'
1486
 alt='".__('Warning')."'>&nbsp;".
1487
 __('Warning: The request exceeds the limit of the directory. The results are only partial.');
1488
 echo "</th></tr></table><div>";
1489
 }
1490
 }
1491
1492
1493
 /**
1494
 * Show LDAP users to add or synchronise
1495
 *
1496
 * @return void
1497
 */
1498
 static function showLdapUsers() {
1499
1500
 $values = [
1501
 'order' => 'DESC',
1502
 'start' => 0,
1503
 ];
1504
1505
 foreach ($_SESSION['ldap_import'] as $option => $value) {
1506
 $values[$option] = $value;
1507
 }
1508
1509
 $rand = mt_rand();
1510
 $results = [];
1511
 $limitexceeded = false;
1512
 $ldap_users = self::getUsers($values, $results, $limitexceeded);
1513
1514
 $config_ldap = new AuthLDAP();
1515
 $config_ldap->getFromDB($values['authldaps_id']);
1516
1517
 if (is_array($ldap_users)) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (3)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

The condition is_array($ldap_users) is always true.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (4) Loading history...

1518
 $numrows = count($ldap_users);
1519
1520
 if ($numrows > 0) {
1521
 self::displaySizeLimitWarning($limitexceeded);
1522
1523
 Html::printPager($values['start'], $numrows, $_SERVER['PHP_SELF'], '');
1524
1525
 // delete end
1526
 array_splice($ldap_users, $values['start'] + $_SESSION['glpilist_limit']);
1527
 // delete begin
1528
 if ($values['start'] > 0) {
1529
 array_splice($ldap_users, 0, $values['start']);
1530
 }
1531
1532
 $form_action = '';
1533
 $textbutton = '';
1534
 if ($_SESSION['ldap_import']['mode']) {
1535
 $textbutton = _x('button', 'Synchronize');
1536
 $form_action = __CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'sync';
1537
 } else {
1538
 $textbutton = _x('button', 'Import');
1539
 $form_action = __CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'import';
1540
 }
1541
1542
 Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
1543
 $massiveactionparams = ['num_displayed' => min(count($ldap_users),
1544
 $_SESSION['glpilist_limit']),
1545
 'container' => 'mass'.__CLASS__.$rand,
1546
 'specific_actions' => [$form_action => $textbutton]];
1547
 Html::showMassiveActions($massiveactionparams);
1548
1549
 echo "<table class='tab_cadre_fixe'>";
1550
 echo "<tr>";
1551
 echo "<th width='10'>";
1552
 echo Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
1553
 echo "</th>";
1554
 $num = 0;
1555
 if ($config_ldap->isSyncFieldEnabled()) {
1556
 echo Search::showHeaderItem(Search::HTML_OUTPUT, __('Synchronization field'), $num,
1557
 $_SERVER['PHP_SELF'].
1558
 "?order=".($values['order']=="DESC"?"ASC":"DESC"));
1559
 }
1560
 echo Search::showHeaderItem(Search::HTML_OUTPUT, User::getTypeName(Session::getPluralNumber()), $num,
1561
 $_SERVER['PHP_SELF'].
1562
 "?order=".($values['order']=="DESC"?"ASC":"DESC"));
1563
 echo "<th>".__('Last update in the LDAP directory')."</th>";
1564
 if ($_SESSION['ldap_import']['mode']) {
1565
 echo "<th>".__('Last update in GLPI')."</th>";
1566
 }
1567
 echo "</tr>";
1568
1569
 foreach ($ldap_users as $userinfos) {
1570
 echo "<tr class='tab_bg_2 center'>";
1571
 //Need to use " instead of ' because it doesn't work with names with ' inside !
1572
 echo "<td>";
1573
 echo Html::getMassiveActionCheckBox(__CLASS__, $userinfos['uid']);
1574
 echo "</td>";
1575
 if ($config_ldap->isSyncFieldEnabled()) {
1576
 echo "<td>" . $userinfos['uid'] . "</td>";
1577
 }
1578
 echo "<td>";
1579
 if (isset($userinfos['id']) && User::canView()) {
1580
 echo "<a href='".$userinfos['link']."'>". $userinfos['name'] . "</a>";
1581
 } else {
1582
 echo $userinfos['link'];
1583
 }
1584
 echo "</td>";
1585
1586
 if ($userinfos['stamp'] != '') {
1587
 echo "<td>" .Html::convDateTime(date("Y-m-d H:i:s", $userinfos['stamp'])). "</td>";
1588
 } else {
1589
 echo "<td>&nbsp;</td>";
1590
 }
1591
 if ($_SESSION['ldap_import']['mode']) {
1592
 if ($userinfos['date_sync'] != '') {
1593
 echo "<td>" . Html::convDateTime($userinfos['date_sync']) . "</td>";
1594
 }
1595
 }
1596
 echo "</tr>";
1597
 }
1598
 echo "<tr>";
1599
 echo "<th width='10'>";
1600
 echo Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
1601
 echo "</th>";
1602
 $num = 0;
1603
1604
 if ($config_ldap->isSyncFieldEnabled()) {
1605
 echo Search::showHeaderItem(Search::HTML_OUTPUT, __('Synchronization field'), $num,
1606
 $_SERVER['PHP_SELF'].
1607
 "?order=".($values['order']=="DESC"?"ASC":"DESC"));
1608
 }
1609
 echo Search::showHeaderItem(Search::HTML_OUTPUT, User::getTypeName(Session::getPluralNumber()), $num,
1610
 $_SERVER['PHP_SELF'].
1611
 "?order=".($values['order']=="DESC"?"ASC":"DESC"));
1612
 echo "<th>".__('Last update in the LDAP directory')."</th>";
1613
 if ($_SESSION['ldap_import']['mode']) {
1614
 echo "<th>".__('Last update in GLPI')."</th>";
1615
 }
1616
 echo "</tr>";
1617
 echo "</table>";
1618
1619
 $massiveactionparams['ontop'] = false;
1620
 Html::showMassiveActions($massiveactionparams);
1621
 Html::closeForm();
1622
1623
 Html::printPager($values['start'], $numrows, $_SERVER['PHP_SELF'], '');
1624
 } else {
1625
 echo "<div class='center b'>".
1626
 ($_SESSION['ldap_import']['mode']?__('No user to be synchronized')
1627
 :__('No user to be imported'))."</div>";
1628
 }
1629
 } else {
1630
 echo "<div class='center b'>".
1631
 ($_SESSION['ldap_import']['mode']?__('No user to be synchronized')
1632
 :__('No user to be imported'))."</div>";
1633
 }
1634
 }
1635
1636
 /**
1637
 * Search users
1638
 *
1639
 * @param resource $ds An LDAP link identifier
1640
 * @param array $values values to search
1641
 * @param string $filter search filter
1642
 * @param array $attrs An array of the required attributes
1643
 * @param boolean $limitexceeded is limit exceeded
1644
 * @param array $user_infos user informations
1645
 * @param array $ldap_users ldap users
1646
 * @param object $config_ldap ldap configuration
1647
 *
1648
 * @return boolean
1649
 */
1650
 static function searchForUsers($ds, $values, $filter, $attrs, &$limitexceeded, &$user_infos,
1651
 &$ldap_users, $config_ldap) {
1652
1653
 //If paged results cannot be used (PHP < 5.4)
1654
 $cookie = ''; //Cookie used to perform query using pages
1655
 $count = 0; //Store the number of results ldap_search
1656
1657
 do {
1658
 $filter = Toolbox::unclean_cross_side_scripting_deep(Toolbox::stripslashes_deep($filter));
1659
 if (self::isLdapPageSizeAvailable($config_ldap)) {
1660
 if (version_compare(PHP_VERSION, '7.3') < 0) {
1661
 //prior to PHP 7.3, use ldap_control_paged_result
1662
 // phpcs:ignore Generic.PHP.DeprecatedFunctions
1663
 ldap_control_paged_result($ds, $config_ldap->fields['pagesize'], true, $cookie);
1664
 $sr = @ldap_search($ds, $values['basedn'], $filter, $attrs);
1665
 } else {
1666
 //since PHP 7.3, send serverctrls to ldap_search
1667
 $controls = [
1668
 [
1669
 'oid' =>LDAP_CONTROL_PAGEDRESULTS,
1670
 'iscritical' => true,
1671
 'value' => [
1672
 'size' => $config_ldap->fields['pagesize'],
1673
 'cookie' => $cookie
1674
 ]
1675
 ]
1676
 ];
1677
 $sr = @ldap_search($ds, $values['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
1678
 ldap_parse_result($ds, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls);
1679
 if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) {
1680
 $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'];
1681
 } else {
1682
 $cookie = '';
1683
 }
1684
 }
1685
 } else {
1686
 $sr = @ldap_search($ds, $values['basedn'], $filter, $attrs);
1687
 }
1688
1689
 if ($sr) {
1690
 if (in_array(ldap_errno($ds), [4,11])) {
1691
 // openldap return 4 for Size limit exceeded
1692
 $limitexceeded = true;
1693
 }
1694
1695
 $info = self::get_entries_clean($ds, $sr);
1696
 if (in_array(ldap_errno($ds), [4,11])) {
1697
 // openldap return 4 for Size limit exceeded
1698
 $limitexceeded = true;
1699
 }
1700
1701
 $count += $info['count'];
1702
 //If page results are enabled and the number of results is greater than the maximum allowed
1703
 //warn user that limit is exceeded and stop search
1704
 if (self::isLdapPageSizeAvailable($config_ldap)
1705
 && $config_ldap->fields['ldap_maxlimit']
1706
 && ($count > $config_ldap->fields['ldap_maxlimit'])) {
1707
 $limitexceeded = true;
1708
 break;
1709
 }
1710
1711
 $field_for_sync = $config_ldap->getLdapIdentifierToUse();
1712
 $login_field = $config_ldap->fields['login_field'];
1713
1714
 for ($ligne = 0; $ligne < $info["count"]; $ligne++) {
1715
 if (in_array($field_for_sync, $info[$ligne])) {
1716
 $uid = self::getFieldValue($info[$ligne], $field_for_sync);
1717
1718
 if ($login_field != $field_for_sync && !isset($info[$ligne][$login_field])) {
1719
 Toolbox::logWarning("Missing field $login_field for LDAP entry $field_for_sync $uid");
1720
 //Login field may be missing... Skip the user
1721
 continue;
1722
 }
1723
1724
 $user_infos[$uid]["timestamp"] = self::ldapStamp2UnixStamp(
1725
 $info[$ligne]['modifytimestamp'][0],
1726
 $config_ldap->fields['time_offset']
1727
 );
1728
 $user_infos[$uid]["user_dn"] = $info[$ligne]['dn'];
1729
 $user_infos[$uid][$field_for_sync] = $uid;
1730
 if ($config_ldap->isSyncFieldEnabled()) {
1731
 $user_infos[$uid][$login_field] = $info[$ligne][$login_field][0];
1732
 }
1733
1734
 if ($values['mode'] == self::ACTION_IMPORT) {
1735
 //If ldap add
1736
 $ldap_users[$uid] = $uid;
1737
 } else {
1738
 //If ldap synchronisation
1739
 $ldap_users[$uid] = self::ldapStamp2UnixStamp(
1740
 $info[$ligne]['modifytimestamp'][0],
1741
 $config_ldap->fields['time_offset']
1742
 );
1743
 $user_infos[$uid]["name"] = $info[$ligne][$login_field][0];
1744
 }
1745
 }
1746
 }
1747
 } else {
1748
 return false;
1749
 }
1750
 if (self::isLdapPageSizeAvailable($config_ldap) && version_compare(PHP_VERSION, '7.3') < 0) {
1751
 // phpcs:ignore Generic.PHP.DeprecatedFunctions
1752
 ldap_control_paged_result_response($ds, $sr, $cookie);
1753
 }
1754
1755
 } while (($cookie !== null) && ($cookie != ''));
1756
 return true;
1757
 }
1758
1759
1760
 /**
1761
 * Get the list of LDAP users to add/synchronize
1762
 *
1763
 * @param array $options possible options:
1764
 * - authldaps_id ID of the server to use
1765
 * - mode user to synchronise or add?
1766
 * - ldap_filter ldap filter to use
1767
 * - basedn force basedn (default authldaps_id one)
1768
 * - order display order
1769
 * - begin_date begin date to time limit
1770
 * - end_date end date to time limit
1771
 * - script true if called by an external script
1772
 * @param array $results result stats
1773
 * @param boolean $limitexceeded limit exceeded exception
1774
 *
1775
 * @return array of the user
1776
 */
1777
 static function getAllUsers(array $options, &$results, &$limitexceeded) {
1778
 global $DB;
1779
1780
 $config_ldap = new self();
1781
 $res = $config_ldap->getFromDB($options['authldaps_id']);
1782
1783
 $values = [
1784
 'order' => 'DESC',
1785
 'mode' => self::ACTION_SYNCHRONIZE,
1786
 'ldap_filter' => '',
1787
 'basedn' => $config_ldap->fields['basedn'],
1788
 'begin_date' => null,
1789
 'end_date' => date('Y-m-d H:i:s', time()-DAY_TIMESTAMP),
1790
 'script' => 0, //Called by an external script or not
1791
 ];
1792
1793
 foreach ($options as $option => $value) {
1794
 // this test break mode detection - if ($value != '') {
1795
 $values[$option] = $value;
1796
 //}
1797
 }
1798
1799
 $ldap_users = [];
1800
 $user_infos = [];
1801
 $limitexceeded = false;
1802
1803
 // we prevent some delay...
1804
 if (!$res) {
1805
 return false;
1806
 }
1807
 if ($values['order'] != "DESC") {
1808
 $values['order'] = "ASC";
1809
 }
1810
 $ds = $config_ldap->connect();
1811
 $field_for_sync = $config_ldap->getLdapIdentifierToUse();
1812
 $field_for_db = $config_ldap->getDatabaseIdentifierToUse();
1813
 if ($ds) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (5)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

$ds is of type resource, thus it always evaluated to false.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (6) Loading history...

1814
 //Search for ldap login AND modifyTimestamp,
1815
 //which indicates the last update of the object in directory
1816
 $attrs = [$config_ldap->fields['login_field'], "modifyTimestamp"];
1817
 if ($field_for_sync != $config_ldap->fields['login_field']) {
1818
 $attrs[] = $field_for_sync;
1819
 }
1820
1821
 // Try a search to find the DN
1822
 if ($values['ldap_filter'] == '') {
1823
 $filter = "(".$field_for_sync."=*)";
1824
 if (!empty($config_ldap->fields['condition'])) {
1825
 $filter = "(& $filter ".$config_ldap->fields['condition'].")";
1826
 }
1827
 } else {
1828
 $filter = $values['ldap_filter'];
1829
 }
1830
1831
 if ($values['script'] && !empty($values['begin_date'])) {
1832
 $filter_timestamp = self::addTimestampRestrictions($values['begin_date'],
1833
 $values['end_date']);
1834
 $filter = "(&$filter $filter_timestamp)";
1835
 }
1836
 $result = self::searchForUsers($ds, $values, $filter, $attrs, $limitexceeded,
1837
 $user_infos, $ldap_users, $config_ldap);
1838
 if (!$result) {
1839
 return false;
1840
 }
1841
 } else {
1842
 return false;
1843
 }
1844
1845
 $glpi_users = [];
1846
1847
 $select = [
1848
 'FROM' => User::getTable(),
1849
 'ORDER' => ['name ' . $values['order']]
1850
 ];
1851
1852
 if ($values['mode'] != self::ACTION_IMPORT) {
1853
 $select['WHERE'] = [
1854
 'authtype' => [-1, Auth::NOT_YET_AUTHENTIFIED, Auth::LDAP, Auth::EXTERNAL, Auth::CAS],
1855
 'auths_id' => $options['authldaps_id']
1856
 ];
1857
 }
1858
1859
 $iterator = $DB->request($select);
1860
1861
 while ($user = $iterator->next()) {
1862
 $tmpuser = new User();
1863
1864
 //Ldap add : fill the array with the login of the user
1865
 if ($values['mode'] == self::ACTION_IMPORT) {
1866
 $glpi_users[$user['name']] = $user['name'];
1867
 } else {
1868
 //Ldap synchronisation : look if the user exists in the directory
1869
 //and compares the modifications dates (ldap and glpi db)
1870
 $userfound = self::dnExistsInLdap($user_infos, $user['user_dn']);
1871
 if (!empty($ldap_users[$user[$field_for_db]]) || $userfound) {
1872
 // userfound seems that user dn is present in GLPI DB but do not correspond to an GLPI user
1873
 // -> renaming case
1874
 if ($userfound) {
1875
 //Get user in DB with this dn
1876
 if (!$tmpuser->getFromDBByDn(Toolbox::addslashes_deep($user['user_dn']))) {
1877
 //This should never happened
1878
 //If a user_dn is present more than one time in database
1879
 //Just skip user synchronization to avoid errors
1880
 continue;
1881
 }
1882
 $glpi_users[] = ['id' => $user['id'],
1883
 'user' => $userfound['name'],
1884
 $field_for_sync => (isset($userfound[$config_ldap->fields['sync_field']]) ? $userfound[$config_ldap->fields['sync_field']] : 'NULL'),
1885
 'timestamp' => $user_infos[$userfound[$field_for_sync]]['timestamp'],
1886
 'date_sync' => $tmpuser->fields['date_sync'],
1887
 'dn' => $user['user_dn']];
1888
 } else if (($values['mode'] == self::ACTION_ALL)
1889
 || (($ldap_users[$user[$field_for_db]] - strtotime($user['date_sync'])) > 0)) {
1890
 //If entry was modified or if script should synchronize all the users
1891
 $glpi_users[] = ['id' => $user['id'],
1892
 'user' => $user['name'],
1893
 $field_for_sync => $user['sync_field'],
1894
 'timestamp' => $user_infos[$user[$field_for_db]]['timestamp'],
1895
 'date_sync' => $user['date_sync'],
1896
 'dn' => $user['user_dn']];
1897
 }
1898
1899
 } else if (($values['mode'] == self::ACTION_ALL)
1900
 && !$limitexceeded) {
1901
 // Only manage deleted user if ALL (because of entity visibility in delegated mode)
1902
1903
 //If user is marked as coming from LDAP, but is not present in it anymore
1904
 if (!$user['is_deleted']
1905
 && ($user['auths_id'] == $options['authldaps_id'])) {
1906
 User::manageDeletedUserInLdap($user['id']);
1907
 $results[self::USER_DELETED_LDAP] ++;
1908
 }
1909
 }
1910
 }
1911
 }
1912
1913
 //If add, do the difference between ldap users and glpi users
1914
 if ($values['mode'] == self::ACTION_IMPORT) {
1915
 $diff = array_diff_ukey($ldap_users, $glpi_users, 'strcasecmp');
1916
 $list = [];
1917
 $tmpuser = new User();
1918
1919
 foreach ($diff as $user) {
1920
 //If user dn exists in DB, it means that user login field has changed
1921
 if (!$tmpuser->getFromDBByDn(Toolbox::addslashes_deep($user_infos[$user]["user_dn"]))) {
1922
 $entry = ["user" => $user_infos[$user][$config_ldap->fields['login_field']],
1923
 "timestamp" => $user_infos[$user]["timestamp"],
1924
 "date_sync" => Dropdown::EMPTY_VALUE];
1925
 if ($config_ldap->isSyncFieldEnabled()) {
1926
 $entry[$field_for_sync] = $user_infos[$user][$field_for_sync];
1927
 }
1928
 $list[] = $entry;
1929
 }
1930
 }
1931
 if ($values['order'] == 'DESC') {
1932
 rsort($list);
1933
 } else {
1934
 sort($list);
1935
 }
1936
1937
 return $list;
1938
 }
1939
 return $glpi_users;
1940
 }
1941
1942
1943
 /**
1944
 * Check if a user DN exists in a ldap user search result
1945
 *
1946
 * @since 0.84
1947
 *
1948
 * @param array $ldap_infos ldap user search result
1949
 * @param string $user_dn user dn to look for
1950
 *
1951
 * @return boolean false if the user dn doesn't exist, user ldap infos otherwise
1952
 */
1953
 static function dnExistsInLdap($ldap_infos, $user_dn) {
1954
1955
 $found = false;
1956
 foreach ($ldap_infos as $ldap_info) {
1957
 if ($ldap_info['user_dn'] == $user_dn) {
1958
 $found = $ldap_info;
1959
 break;
1960
 }
1961
 }
1962
 return $found;
1963
 }
1964
1965
1966
 /**
1967
 * Show LDAP groups to add or synchronize in an entity
1968
 *
1969
 * @param string $target target page for the form
1970
 * @param integer $start where to start the list
1971
 * @param integer $sync synchronize or add? (default 0)
1972
 * @param string $filter ldap filter to use (default '')
1973
 * @param string $filter2 second ldap filter to use (which case?) (default '')
1974
 * @param integer $entity working entity
1975
 * @param string $order display order (default DESC)
1976
 *
1977
 * @return void
1978
 */
1979
 static function showLdapGroups($target, $start, $sync = 0, $filter = '', $filter2 = '',
1980
 $entity = 0, $order = 'DESC') {
1981
1982
 echo "<br>";
1983
 $limitexceeded = false;
1984
 $ldap_groups = self::getAllGroups($_SESSION["ldap_server"], $filter, $filter2, $entity,
1985
 $limitexceeded, $order);
1986
1987
 if (is_array($ldap_groups)) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (7)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

The condition is_array($ldap_groups) is always true.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (8) Loading history...

1988
 $numrows = count($ldap_groups);
1989
 $rand = mt_rand();
1990
 if ($numrows > 0) {
1991
 self::displaySizeLimitWarning($limitexceeded);
1992
 $parameters = '';
1993
 Html::printPager($start, $numrows, $target, $parameters);
1994
1995
 // delete end
1996
 array_splice($ldap_groups, $start + $_SESSION['glpilist_limit']);
1997
 // delete begin
1998
 if ($start > 0) {
1999
 array_splice($ldap_groups, 0, $start);
2000
 }
2001
2002
 echo "<div class='center'>";
2003
 Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
2004
 $massiveactionparams
2005
 = ['num_displayed'
2006
 => min($_SESSION['glpilist_limit'], count($ldap_groups)),
2007
 'container'
2008
 => 'mass'.__CLASS__.$rand,
2009
 'specific_actions'
2010
 => [__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'import_group'
2011
 => _sx('button', 'Import')],
2012
 'extraparams'
2013
 => ['massive_action_fields' => ['dn', 'ldap_import_type',
2014
 'ldap_import_entities',
2015
 'ldap_import_recursive']]];
2016
 Html::showMassiveActions($massiveactionparams);
2017
2018
 echo "<table class='tab_cadre_fixe'>";
2019
 echo "<tr>";
2020
 echo "<th width='10'>";
2021
 Html::showCheckbox(['criterion' => ['tag_for_massive' => 'select_item']]);
2022
 echo "</th>";
2023
 $header_num = 0;
2024
 echo Search::showHeaderItem(Search::HTML_OUTPUT, Group::getTypeName(1), $header_num,
2025
 $target."?order=".($order=="DESC"?"ASC":"DESC"),
2026
 1, $order);
2027
 echo "<th>".__('Group DN')."</th>";
2028
 echo "<th>".__('Destination entity')."</th>";
2029
 if (Session::isMultiEntitiesMode()) {
2030
 echo"<th>";
2031
 Html::showCheckbox(['criterion' => ['tag_for_massive' => 'select_item_child_entities']]);
2032
 echo "&nbsp;".__('Child entities');
2033
 echo "</th>";
2034
 }
2035
 echo "</tr>";
2036
2037
 $dn_index = 0;
2038
 foreach ($ldap_groups as $groupinfos) {
2039
 $group = $groupinfos["cn"];
2040
 $group_dn = $groupinfos["dn"];
2041
 $search_type = $groupinfos["search_type"];
2042
2043
 echo "<tr class='tab_bg_2 center'>";
2044
 echo "<td>";
2045
 echo Html::hidden("dn[$dn_index]", ['value' => $group_dn,
2046
 'data-glpicore-ma-tags' => 'common']);
2047
 echo Html::hidden("ldap_import_type[$dn_index]", ['value' => $search_type,
2048
 'data-glpicore-ma-tags' => 'common']);
2049
 Html::showMassiveActionCheckBox(__CLASS__, $dn_index,
2050
 ['massive_tags' => 'select_item']);
2051
 echo "</td>";
2052
 echo "<td>" . $group . "</td>";
2053
 echo "<td>" .$group_dn. "</td>";
2054
 echo "<td>";
2055
 Entity::dropdown(['value' => $entity,
2056
 'name' => "ldap_import_entities[$dn_index]",
2057
 'specific_tags' => ['data-glpicore-ma-tags' => 'common']]);
2058
 echo "</td>";
2059
 if (Session::isMultiEntitiesMode()) {
2060
 echo "<td>";
2061
 Html::showMassiveActionCheckBox(__CLASS__, $dn_index,
2062
 ['massive_tags' => 'select_item_child_entities',
2063
 'name' => "ldap_import_recursive[$dn_index]",
2064
 'specific_tags' => ['data-glpicore-ma-tags' => 'entities_id']]);
2065
 echo "</td>";
2066
 } else {
2067
 echo Html::hidden("ldap_import_recursive[$dn_index]", ['value' => 0,
2068
 'data-glpicore-ma-tags' => 'entities_id']);
2069
 }
2070
 echo "</tr>\n";
2071
 $dn_index++;
2072
 }
2073
2074
 $massiveactionparams['ontop'] = false;
2075
 Html::showMassiveActions($massiveactionparams);
2076
 Html::closeForm();
2077
 echo "</div>";
2078
 Html::printPager($start, $numrows, $target, $parameters);
2079
2080
 } else {
2081
 echo "<div class='center b'>" . __('No group to be imported') . "</div>";
2082
 }
2083
 } else {
2084
 echo "<div class='center b'>" . __('No group to be imported') . "</div>";
2085
 }
2086
 }
2087
2088
2089
 /**
2090
 * Get all LDAP groups from a ldap server which are not already in an entity
2091
 *
2092
 * @since 0.84 new parameter $limitexceeded
2093
 *
2094
 * @param integer $auths_id ID of the server to use
2095
 * @param string $filter ldap filter to use
2096
 * @param string $filter2 second ldap filter to use if needed
2097
 * @param string $entity entity to search
2098
 * @param boolean $limitexceeded is limit exceeded
2099
 * @param string $order order to use (default DESC)
2100
 *
2101
 * @return array of the groups
2102
 */
2103
 static function getAllGroups($auths_id, $filter, $filter2, $entity, &$limitexceeded,
2104
 $order = 'DESC') {
2105
 global $DB;
2106
2107
 $config_ldap = new self();
2108
 $config_ldap->getFromDB($auths_id);
2109
 $infos = [];
2110
 $groups = [];
2111
2112
 $ds = $config_ldap->connect();
2113
 if ($ds) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (9)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

$ds is of type resource, thus it always evaluated to false.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (10) Loading history...

2114
 switch ($config_ldap->fields["group_search_type"]) {
2115
 case self::GROUP_SEARCH_USER:
2116
 $infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter,
2117
 $limitexceeded, false, $infos);
2118
 break;
2119
2120
 case self::GROUP_SEARCH_GROUP:
2121
 $infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter,
2122
 $limitexceeded, true, $infos);
2123
 break;
2124
2125
 case self::GROUP_SEARCH_BOTH:
2126
 $infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter,
2127
 $limitexceeded, true, $infos);
2128
 $infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter2,
2129
 $limitexceeded, false, $infos);
2130
 break;
2131
 }
2132
 if (!empty($infos)) {
2133
 $glpi_groups = [];
2134
2135
 //Get all groups from GLPI DB for the current entity and the subentities
2136
 $iterator = $DB->request([
2137
 'SELECT' => ['ldap_group_dn','ldap_value'],
2138
 'FROM' => 'glpi_groups',
2139
 'WHERE' => getEntitiesRestrictCriteria('glpi_groups')
2140
 ]);
2141
2142
 //If the group exists in DB -> unset it from the LDAP groups
2143
 while ($group = $iterator->next()) {
2144
 //use DN for next step
2145
 //depending on the type of search when groups are imported
2146
 //the DN may be in two separate fields
2147
 if (isset($group["ldap_group_dn"]) && !empty($group["ldap_group_dn"])) {
2148
 $glpi_groups[$group["ldap_group_dn"]] = 1;
2149
 } else if (isset($group["ldap_value"]) && !empty($group["ldap_value"])) {
2150
 $glpi_groups[$group["ldap_value"]] = 1;
2151
 }
2152
 }
2153
 $ligne = 0;
2154
2155
 foreach ($infos as $dn => $info) {
2156
 //reconcile by DN
2157
 if (!isset($glpi_groups[$dn])) {
2158
 $groups[$ligne]["dn"] = $dn;
2159
 $groups[$ligne]["cn"] = $info["cn"];
2160
 $groups[$ligne]["search_type"] = $info["search_type"];
2161
 $ligne++;
2162
 }
2163
 }
2164
 }
2165
2166
 if ($order == 'DESC') {
2167
 function local_cmp($b, $a) {
2168
 return strcasecmp($a['cn'], $b['cn']);
2169
 }
2170
2171
 } else {
2172
 function local_cmp($a, $b) {
2173
 return strcasecmp($a['cn'], $b['cn']);
2174
 }
2175
 }
2176
 usort($groups, 'local_cmp');
2177
2178
 }
2179
 return $groups;
2180
 }
2181
2182
2183
 /**
2184
 * Get the group's cn by giving his DN
2185
 *
2186
 * @param resource $ldap_connection ldap connection to use
2187
 * @param string $group_dn the group's dn
2188
 *
2189
 * @return string the group cn
2190
 */
2191
 static function getGroupCNByDn($ldap_connection, $group_dn) {
2192
2193
 $sr = @ ldap_read($ldap_connection, $group_dn, "objectClass=*", ["cn"]);
2194
 if ($sr === false) {
2195
 //group does not exists
2196
 return false;
2197
 }
2198
 $v = self::get_entries_clean($ldap_connection, $sr);
2199
 if (!is_array($v) || (count($v) == 0) || empty($v[0]["cn"][0])) {
2200
 return false;
2201
 }
2202
 return $v[0]["cn"][0];
2203
 }
2204
2205
2206
 /**
2207
 * Set groups from ldap
2208
 *
2209
 * @since 0.84 new parameter $limitexceeded
2210
 *
2211
 * @param resource $ldap_connection LDAP connection
2212
 * @param object $config_ldap LDAP configuration
2213
 * @param string $filter Filters
2214
 * @param boolean $limitexceeded Is limit exceeded
2215
 * @param boolean $search_in_groups Search in groups (true by default)
2216
 * @param array $groups Groups to search
2217
 *
2218
 * @return array
2219
 */
2220
 static function getGroupsFromLDAP($ldap_connection, $config_ldap, $filter,
2221
 &$limitexceeded, $search_in_groups = true,
2222
 $groups = []) {
2223
 global $DB;
2224
2225
 //First look for groups in group objects
2226
 $extra_attribute = ($search_in_groups?"cn":$config_ldap->fields["group_field"]);
2227
 $attrs = ["dn", $extra_attribute];
2228
2229
 if ($filter == '') {
2230
 if ($search_in_groups) {
2231
 $filter = (!empty($config_ldap->fields['group_condition'])
2232
 ? $config_ldap->fields['group_condition'] : "(objectclass=*)");
2233
 } else {
2234
 $filter = (!empty($config_ldap->fields['condition'])
2235
 ? $config_ldap->fields['condition'] : "(objectclass=*)");
2236
 }
2237
 }
2238
 $cookie = '';
2239
 $count = 0;
2240
 do {
2241
 $filter = Toolbox::unclean_cross_side_scripting_deep(Toolbox::stripslashes_deep($filter));
2242
 if (self::isLdapPageSizeAvailable($config_ldap)) {
2243
 if (version_compare(PHP_VERSION, '7.3') < 0) {
2244
 //prior to PHP 7.3, use ldap_control_paged_result
2245
 // phpcs:ignore Generic.PHP.DeprecatedFunctions
2246
 ldap_control_paged_result($ldap_connection, $config_ldap->fields['pagesize'], true, $cookie);
2247
 $sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs);
2248
 } else {
2249
 //since PHP 7.3, send serverctrls to ldap_search
2250
 $controls = [
2251
 [
2252
 'oid' =>LDAP_CONTROL_PAGEDRESULTS,
2253
 'iscritical' => true,
2254
 'value' => [
2255
 'size' => $config_ldap->fields['pagesize'],
2256
 'cookie' => $cookie
2257
 ]
2258
 ]
2259
 ];
2260
 $sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
2261
 ldap_parse_result($ldap_connection, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls);
2262
 if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) {
2263
 $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'];
2264
 } else {
2265
 $cookie = '';
2266
 }
2267
 }
2268
 } else {
2269
 $sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs);
2270
 }
2271
2272
 if ($sr) {
2273
 if (in_array(ldap_errno($ldap_connection), [4,11])) {
2274
 // openldap return 4 for Size limit exceeded
2275
 $limitexceeded = true;
2276
 }
2277
2278
 $infos = self::get_entries_clean($ldap_connection, $sr);
2279
 if (in_array(ldap_errno($ldap_connection), [4,11])) {
2280
 // openldap return 4 for Size limit exceeded
2281
 $limitexceeded = true;
2282
 }
2283
2284
 $count += $infos['count'];
2285
 //If page results are enabled and the number of results is greater than the maximum allowed
2286
 //warn user that limit is exceeded and stop search
2287
 if (self::isLdapPageSizeAvailable($config_ldap)
2288
 && $config_ldap->fields['ldap_maxlimit']
2289
 && ($count > $config_ldap->fields['ldap_maxlimit'])) {
2290
 $limitexceeded = true;
2291
 break;
2292
 }
2293
2294
 for ($ligne=0; $ligne < $infos["count"]; $ligne++) {
2295
 if ($search_in_groups) {
2296
 // No cn : not a real object
2297
 if (isset($infos[$ligne]["cn"][0])) {
2298
 $groups[$infos[$ligne]["dn"]] = (["cn" => $infos[$ligne]["cn"][0],
2299
 "search_type" => "groups"]);
2300
 }
2301
2302
 } else {
2303
 if (isset($infos[$ligne][$extra_attribute])) {
2304
 if (($config_ldap->fields["group_field"] == 'dn')
2305
 || in_array('ou', $groups)) {
2306
 $dn = $infos[$ligne][$extra_attribute];
2307
 $ou = [];
2308
 for ($tmp=$dn; count($tmptab = explode(',', $tmp, 2))==2; $tmp=$tmptab[1]) {
2309
 $ou[] = $tmptab[1];
2310
 }
2311
2312
 /// Search in DB for group with ldap_group_dn
2313
 if (($config_ldap->fields["group_field"] == 'dn')
2314
 && (count($ou) > 0)) {
2315
 $iterator = $DB->request([
2316
 'SELECT' => ['ldap_value'],
2317
 'FROM' => 'glpi_groups',
2318
 'WHERE' => [
2319
 'ldap_group_dn' => Toolbox::addslashes_deep($ou)
2320
 ]
2321
 ]);
2322
2323
 while ($group = $iterator->next()) {
2324
 $groups[$group['ldap_value']] = ["cn" => $group['ldap_value'],
2325
 "search_type" => "users"];
2326
 }
2327
 }
2328
2329
 } else {
2330
 for ($ligne_extra=0; $ligne_extra<$infos[$ligne][$extra_attribute]["count"];
2331
 $ligne_extra++) {
2332
 $groups[$infos[$ligne][$extra_attribute][$ligne_extra]]
2333
 = ["cn" => self::getGroupCNByDn($ldap_connection,
2334
 $infos[$ligne][$extra_attribute][$ligne_extra]),
2335
 "search_type"
2336
 => "users"];
2337
 }
2338
 }
2339
 }
2340
 }
2341
 }
2342
 }
2343
 if (self::isLdapPageSizeAvailable($config_ldap) && version_compare(PHP_VERSION, '7.3') < 0) {
2344
 // phpcs:ignore Generic.PHP.DeprecatedFunctions
2345
 ldap_control_paged_result_response($ldap_connection, $sr, $cookie);
2346
 }
2347
 } while (($cookie !== null) && ($cookie != ''));
2348
2349
 return $groups;
2350
 }
2351
2352
2353
 /**
2354
 * Form to choose a ldap server
2355
 *
2356
 * @param string $target target page for the form
2357
 *
2358
 * @return void
2359
 */
2360
 static function ldapChooseDirectory($target) {
2361
 global $DB;
2362
2363
 $iterator = $DB->request([
2364
 'FROM' => self::getTable(),
2365
 'WHERE' => [
2366
 'is_active' => 1
2367
 ],
2368
 'ORDER' => 'name ASC'
2369
 ]);
2370
2371
 if (count($iterator) == 1) {
2372
 //If only one server, do not show the choose ldap server window
2373
 $ldap = $iterator->next();
2374
 $_SESSION["ldap_server"] = $ldap["id"];
2375
 Html::redirect($_SERVER['PHP_SELF']);
2376
 }
2377
2378
 echo "<div class='center'>";
2379
 echo "<form action='$target' method=\"post\">";
2380
 echo "<p>" . __('Please choose LDAP directory to import users and groups from') . "</p>";
2381
 echo "<table class='tab_cadre_fixe'>";
2382
 echo "<tr class='tab_bg_2'><th colspan='2'>" . __('LDAP directory choice') . "</th></tr>";
2383
2384
 //If more than one ldap server
2385
 if (count($iterator) > 1) {
2386
 echo "<tr class='tab_bg_2'><td class='center'>" . __('Name') . "</td>";
2387
 echo "<td class='center'>";
2388
 AuthLDAP::Dropdown(['name' => 'ldap_server',
2389
 'display_emptychoice' => false,
2390
 'comment' => true,
2391
 'condition' => ['is_active' => 1]]);
2392
 echo "</td></tr>";
2393
2394
 echo "<tr class='tab_bg_2'><td class='center' colspan='2'>";
2395
 echo "<input class='submit' type='submit' name='ldap_showusers' value=\"".
2396
 _sx('button', 'Post') . "\"></td></tr>";
2397
2398
 } else {
2399
 //No ldap server
2400
 echo "<tr class='tab_bg_2'>".
2401
 "<td class='center' colspan='2'>".__('No LDAP directory defined in GLPI')."</td></tr>";
2402
 }
2403
 echo "</table>";
2404
 Html::closeForm();
2405
 echo "</div>";
2406
 }
2407
2408
 /**
2409
 * Force synchronization for one user
2410
 *
2411
 * @param User $user User to synchronize
2412
 * @param boolean $display Display message information on redirect (true by default)
2413
 *
2414
 * @return array|boolean with state, else false
2415
 */
2416
 static function forceOneUserSynchronization(User $user, $display = true) {
2417
 $authldap = new AuthLDAP();
2418
2419
 //Get the LDAP server from which the user has been imported
2420
 if ($authldap->getFromDB($user->fields['auths_id'])) {
2421
 $user_field = 'name';
2422
 $id_field = $authldap->fields['login_field'];
2423
 if ($authldap->isSyncFieldEnabled() && !empty($user->fields['sync_field'])) {
2424
 $user_field = 'sync_field';
2425
 $id_field = $authldap->fields['sync_field'];
2426
 }
2427
 return AuthLDAP::ldapImportUserByServerId(
2428
 [
2429
 'method' => self::IDENTIFIER_LOGIN,
2430
 'value' => $user->fields[$user_field],
2431
 'identifier_field' => $id_field,
2432
 'user_field' => $user_field
2433
 ],
2434
 true,
2435
 $user->fields["auths_id"],
2436
 $display
2437
 );
2438
 }
2439
 return false;
2440
 }
2441
2442
 /**
2443
 * Import a user from a specific ldap server
2444
 *
2445
 * @param array $params of parameters: method (IDENTIFIER_LOGIN or IDENTIFIER_EMAIL) + value
2446
 * @param boolean $action synchoronize (true) or import (false)
2447
 * @param integer $ldap_server ID of the LDAP server to use
2448
 * @param boolean $display display message information on redirect (false by default)
2449
 *
2450
 * @return array|boolean with state, else false
2451
 */
2452
 static function ldapImportUserByServerId(array $params, $action, $ldap_server,
2453
 $display = false) {
2454
2455
 $params = Toolbox::stripslashes_deep($params);
2456
 $config_ldap = new self();
2457
 $res = $config_ldap->getFromDB($ldap_server);
2458
 $input = [];
2459
2460
 // we prevent some delay...
2461
 if (!$res) {
2462
 return false;
2463
 }
2464
2465
 if (!isset($params['identifier_field'])) {
2466
 $params['identifier_field'] = $config_ldap->getLdapIdentifierToUse();
2467
 }
2468
 if (!isset($params['user_field'])) {
2469
 $params['user_field'] = $config_ldap->getDatabaseIdentifierToUse();
2470
 }
2471
2472
 $search_parameters = [];
2473
 //Connect to the directory
2474
 if (isset(self::$conn_cache[$ldap_server])) {
2475
 $ds = self::$conn_cache[$ldap_server];
2476
 } else {
2477
 $ds = $config_ldap->connect();
2478
 }
2479
 if ($ds) {
2480
 self::$conn_cache[$ldap_server] = $ds;
2481
 $search_parameters['method'] = $params['method'];
2482
 $search_parameters['fields'][self::IDENTIFIER_LOGIN] = $params['identifier_field'];
2483
2484
 if ($params['method'] == self::IDENTIFIER_EMAIL) {
2485
 $search_parameters['fields'][self::IDENTIFIER_EMAIL]
2486
 = $config_ldap->fields['email1_field'];
2487
 }
2488
2489
 //Get the user's dn & login
2490
 $attribs = ['basedn' => $config_ldap->fields['basedn'],
2491
 'login_field' => $search_parameters['fields'][$search_parameters['method']],
2492
 'search_parameters' => $search_parameters,
2493
 'user_params' => $params,
2494
 'condition' => $config_ldap->fields['condition']];
2495
2496
 try {
2497
 $infos = self::searchUserDn($ds, $attribs);
2498
2499
 if ($infos && $infos['dn']) {
2500
 $user_dn = $infos['dn'];
2501
 $user = new User();
2502
2503
 $login = self::getFieldValue($infos, $search_parameters['fields'][$search_parameters['method']]);
2504
2505
 //Get information from LDAP
2506
 if ($user->getFromLDAP($ds, $config_ldap->fields, $user_dn, addslashes($login),
2507
 ($action == self::ACTION_IMPORT))) {
2508
 // Add the auth method
2509
 // Force date sync
2510
 $user->fields["date_sync"] = $_SESSION["glpi_currenttime"];
2511
 $user->fields['is_deleted_ldap'] = 0;
2512
2513
 //Save information in database !
2514
 $input = $user->fields;
2515
2516
 //clean picture from input
2517
 // (picture managed in User::post_addItem and prepareInputForUpdate)
2518
 unset($input['picture']);
2519
2520
 if ($action == self::ACTION_IMPORT) {
2521
 $input["authtype"] = Auth::LDAP;
2522
 $input["auths_id"] = $ldap_server;
2523
 // Display message after redirect
2524
 if ($display) {
2525
 $input['add'] = 1;
2526
 }
2527
2528
 $user->fields["id"] = $user->add($input);
2529
 return ['action' => self::USER_IMPORTED,
2530
 'id' => $user->fields["id"]];
2531
 }
2532
 //Get the ID by user name
2533
 if (!($id = User::getIdByfield($params['user_field'], $login))) {
2534
 //In case user id as changed : get id by dn
2535
 $id = User::getIdByfield('user_dn', $user_dn);
2536
 }
2537
 $input['id'] = $id;
2538
2539
 if ($display) {
2540
 $input['update'] = 1;
2541
 }
2542
 $user->update($input);
2543
 return ['action' => self::USER_SYNCHRONIZED,
2544
 'id' => $input['id']];
2545
 }
2546
 return false;
2547
2548
 }
2549
 if ($action != self::ACTION_IMPORT) {
2550
 $users_id = User::getIdByField($params['user_field'], $params['value']);
2551
 User::manageDeletedUserInLdap($users_id);
2552
 return ['action' => self::USER_DELETED_LDAP,
2553
 'id' => $users_id];
2554
 }
2555
 } catch (\RuntimeException $e) {
2556
 Toolbox::logError($e->getMessage());
2557
 return false;
2558
 }
2559
 } else {
2560
 return false;
2561
 }
2562
 }
2563
2564
2565
 /**
2566
 * Import grousp from an LDAP directory
2567
 *
2568
 * @param string $group_dn dn of the group to import
2569
 * @param array $options array for
2570
 * - authldaps_id
2571
 * - entities_id where group must to be imported
2572
 * - is_recursive
2573
 *
2574
 * @return integer|false
2575
 */
2576
 static function ldapImportGroup($group_dn, $options = []) {
2577
2578
 $config_ldap = new self();
2579
 $res = $config_ldap->getFromDB($options['authldaps_id']);
2580
2581
 // we prevent some delay...
2582
 if (!$res) {
2583
 return false;
2584
 }
2585
2586
 //Connect to the directory
2587
 $ds = $config_ldap->connect();
2588
 if ($ds) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (11)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

$ds is of type resource, thus it always evaluated to false.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (12) Loading history...

2589
 $group_infos = self::getGroupByDn($ds, stripslashes($group_dn));
2590
 $group = new Group();
2591
 if ($options['type'] == "groups") {
2592
 return $group->add(["name" => addslashes($group_infos["cn"][0]),
2593
 "ldap_group_dn" => addslashes($group_infos["dn"]),
2594
 "entities_id" => $options['entities_id'],
2595
 "is_recursive" => $options['is_recursive']]);
2596
 }
2597
 return $group->add(["name" => addslashes($group_infos["cn"][0]),
2598
 "ldap_field" => $config_ldap->fields["group_field"],
2599
 "ldap_value" => addslashes($group_infos["dn"]),
2600
 "entities_id" => $options['entities_id'],
2601
 "is_recursive" => $options['is_recursive']]);
2602
 }
2603
 return false;
2604
 }
2605
2606
2607
 /**
2608
 * Open LDAP connection to current server
2609
 *
2610
 * @return resource|boolean
2611
 */
2612
 function connect() {
2613
2614
 return $this->connectToServer($this->fields['host'], $this->fields['port'],
2615
 $this->fields['rootdn'],
2616
 Toolbox::sodiumDecrypt($this->fields['rootdn_passwd']),
2617
 $this->fields['use_tls'],
2618
 $this->fields['deref_option']);
2619
 }
2620
2621
2622
 /**
2623
 * Connect to a LDAP server
2624
 *
2625
 * @param string $host LDAP host to connect
2626
 * @param string $port port to use
2627
 * @param string $login login to use (default '')
2628
 * @param string $password password to use (default '')
2629
 * @param boolean $use_tls use a TLS connection? (false by default)
2630
 * @param integer $deref_options deref options used
2631
 *
2632
 * @return resource link to the LDAP server : false if connection failed
2633
 */
2634
 static function connectToServer($host, $port, $login = "", $password = "",
2635
 $use_tls = false, $deref_options = 0) {
2636
2637
 $ds = @ldap_connect($host, intval($port));
2638
 if ($ds) {

0 ignored issues

show

introduced by Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (13)

  • Report Bug
  • Copy Issue Report
  • Show Similar Issues like this

$ds is of type false|resource, thus it always evaluated to false.

Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (14) Loading history...

2639
 @ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
2640
 @ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
2641
 @ldap_set_option($ds, LDAP_OPT_DEREF, $deref_options);
2642
 if ($use_tls) {
2643
 if ([emailprotected]_start_tls($ds)) {
2644
 return false;
2645
 }
2646
 }
2647
 // Auth bind
2648
 if ($login != '') {
2649
 $b = @ldap_bind($ds, $login, $password);
2650
 } else { // Anonymous bind
2651
 $b = @ldap_bind($ds);
2652
 }
2653
 if ($b) {
2654
 return $ds;
2655
 }
2656
 }
2657
 return false;
2658
 }
2659
2660
2661
 /**
2662
 * Try to connect to a ldap server
2663
 *
2664
 * @param array $ldap_method ldap_method array to use
2665
 * @param string $login User Login
2666
 * @param string $password User Password
2667
 *
2668
 * @return resource|boolean link to the LDAP server : false if connection failed
2669
 */
2670
 static function tryToConnectToServer($ldap_method, $login, $password) {
2671
 if (!function_exists('ldap_connect')) {
2672
 Toolbox::logError("ldap_connect function is missing. Did you miss install php-ldap extension?");
2673
 return false;
2674
 }
2675
 $ds = self::connectToServer($ldap_method['host'], $ldap_method['port'],
2676
 $ldap_method['rootdn'],
2677
 Toolbox::sodiumDecrypt($ldap_method['rootdn_passwd']),
2678
 $ldap_method['use_tls'], $ldap_method['deref_option']);
2679
2680
 // Test with login and password of the user if exists
2681
 if (!$ds
2682
 && !empty($login)) {
2683
 $ds = self::connectToServer($ldap_method['host'], $ldap_method['port'], $login,
2684
 $password, $ldap_method['use_tls'],
2685
 $ldap_method['deref_option']);
2686
 }
2687
2688
 //If connection is not successful on this directory, try replicates (if replicates exists)
2689
 if (!$ds
2690
 && ($ldap_method['id'] > 0)) {
2691
 foreach (self::getAllReplicateForAMaster($ldap_method['id']) as $replicate) {
2692
 $ds = self::connectToServer($replicate["host"], $replicate["port"],
2693
 $ldap_method['rootdn'],
2694
 Toolbox::sodiumDecrypt($ldap_method['rootdn_passwd']),
2695
 $ldap_method['use_tls'], $ldap_method['deref_option']);
2696
2697
 // Test with login and password of the user
2698
 if (!$ds
2699
 && !empty($login)) {
2700
 $ds = self::connectToServer($replicate["host"], $replicate["port"], $login,
2701
 $password, $ldap_method['use_tls'],
2702
 $ldap_method['deref_option']);
2703
 }
2704
 if ($ds) {
2705
 return $ds;
2706
 }
2707
 }
2708
 }
2709
 return $ds;
2710
 }
2711
2712
 /**
2713
 * Get LDAP servers
2714
 *
2715
 * @return array
2716
 */
2717
 static function getLdapServers() {
2718
 return getAllDataFromTable('glpi_authldaps', ['ORDER' => 'is_default DESC']);
2719
 }
2720
2721
2722
 /**
2723
 * Is the LDAP authentication used?
2724
 *
2725
 * @return boolean
2726
 */
2727
 static function useAuthLdap() {
2728
 return (countElementsInTable('glpi_authldaps', ['is_active' => 1]) > 0);
2729
 }
2730
2731
2732
 /**
2733
 * Import a user from ldap
2734
 * Check all the directories. When the user is found, then import it
2735
 *
2736
 * @param array $options array containing condition:
2737
 * array('name'=>'glpi') or array('email' => 'test at test.com')
2738
 *
2739
 * @return array|boolean false if fail
2740
 */
2741
 static function importUserFromServers($options = []) {
2742
2743
 $auth = new Auth();
2744
 $params = [];
2745
 if (isset($options['name'])) {
2746
 $params['value'] = $options['name'];
2747
 $params['method'] = self::IDENTIFIER_LOGIN;
2748
 }
2749
 if (isset($options['email'])) {
2750
 $params['value'] = $options['email'];
2751
 $params['method'] = self::IDENTIFIER_EMAIL;
2752
 }
2753
2754
 $auth->user_present = $auth->userExists($options);
2755
2756
 //If the user does not exists
2757
 if ($auth->user_present == 0) {
2758
 $auth->getAuthMethods();
2759
 $ldap_methods = $auth->authtypes["ldap"];
2760
2761
 foreach ($ldap_methods as $ldap_method) {
2762
 if ($ldap_method['is_active']) {
2763
 //we're looking for a user login
2764
 $params['identifier_field'] = $ldap_method['login_field'];
2765
 $params['user_field'] = 'name';
2766
 $result = self::ldapImportUserByServerId($params, 0, $ldap_method["id"], true);
2767
 if ($result != false) {
2768
 return $result;
2769
 }
2770
 }
2771
 }
2772
 Session::addMessageAfterRedirect(__('User not found or several users found'), false, ERROR);
2773
2774
 } else {
2775
 Session::addMessageAfterRedirect(__('Unable to add. The user already exist.'), false,
2776
 ERROR);
2777
 }
2778
 return false;
2779
 }
2780
2781
2782
 /**
2783
 * Authentify a user by checking a specific directory
2784
 *
2785
 * @param object $auth identification object
2786
 * @param string $login user login
2787
 * @param string $password user password
2788
 * @param array $ldap_method ldap_method array to use
2789
 * @param string $user_dn user LDAP DN if present
2790
 *
2791
 * @return object identification object
2792
 */
2793
 static function ldapAuth($auth, $login, $password, $ldap_method, $user_dn) {
2794
2795
 $oldlevel = error_reporting(0);
2796
2797
 $infos = $auth->connection_ldap($ldap_method, $login, $password);
2798
 $user_dn = $infos['dn'];
2799
 $user_sync = (isset($infos['sync_field']) ? $infos['sync_field'] : null);
2800
2801
 error_reporting($oldlevel);
2802
2803
 $auth->auth_succeded = false;
2804
 $auth->extauth = 1;
2805
2806
 if ($user_dn) {
2807
 $auth->auth_succeded = true;
2808
 // try by login+auth_id and next by dn
2809
 if ($auth->user->getFromDBbyNameAndAuth($login, Auth::LDAP, $ldap_method['id'])
2810
 || $auth->user->getFromDBbyDn(Toolbox::addslashes_deep($user_dn))) {
2811
 //There's already an existing user in DB with the same DN but its login field has changed
2812
 $auth->user->fields['name'] = $login;
2813
 $auth->user_present = true;
2814
 $auth->user_dn = $user_dn;
2815
 } else if ($user_sync !== null && $auth->user->getFromDBbySyncField($user_sync)) {
2816
 //user login/dn have changed
2817
 $auth->user->fields['name'] = $login;
2818
 $auth->user->fields['user_dn'] = $user_dn;
2819
 $auth->user_present = true;
2820
 $auth->user_dn = $user_dn;
2821
 } else { // The user is a new user
2822
 $auth->user_present = false;
2823
 }
2824
 $auth->user->getFromLDAP($auth->ldap_connection, $ldap_method, $user_dn, $login,
2825
 !$auth->user_present);
2826
 $auth->user->fields["authtype"] = Auth::LDAP;
2827
 $auth->user->fields["auths_id"] = $ldap_method["id"];
2828
 }
2829
 return $auth;
2830
 }
2831
2832
2833
 /**
2834
 * Try to authentify a user by checking all the directories
2835
 *
2836
 * @param object $auth identification object
2837
 * @param string $login user login
2838
 * @param string $password user password
2839
 * @param integer $auths_id auths_id already used for the user (default 0)
2840
 * @param boolean $user_dn user LDAP DN if present (false by default)
2841
 * @param boolean $break if user is not found in the first directory,
2842
 * continue searching on the following ones (true by default)
2843
 *
2844
 * @return object identification object
2845
 */
2846
 static function tryLdapAuth($auth, $login, $password, $auths_id = 0, $user_dn = false, $break = true) {
2847
2848
 //If no specific source is given, test all ldap directories
2849
 if ($auths_id <= 0) {
2850
 foreach ($auth->authtypes["ldap"] as $ldap_method) {
2851
 if ($ldap_method['is_active']) {
2852
 $auth = self::ldapAuth($auth, $login, $password, $ldap_method, $user_dn);
2853
2854
 if ($auth->auth_succeded
2855
 && $break) {
2856
 break;
2857
 }
2858
 }
2859
 }
2860
2861
 } else if (array_key_exists($auths_id, $auth->authtypes["ldap"])) {
2862
 // Check if the ldap server indicated as the last good one still exists !
2863
 //A specific ldap directory is given, test it and only this one !
2864
 $auth = self::ldapAuth($auth, $login, $password, $auth->authtypes["ldap"][$auths_id],
2865
 $user_dn);
2866
 }
2867
 return $auth;
2868
 }
2869
2870
2871
 /**
2872
 * Get dn for a user
2873
 *
2874
 * @param resource $ds LDAP link
2875
 * @param array $options array of possible options:
2876
 * - basedn : base dn used to search
2877
 * - login_field : attribute to store login
2878
 * - search_parameters array of search parameters
2879
 * - user_params array of parameters : method (IDENTIFIER_LOGIN or IDENTIFIER_EMAIL) + value
2880
 * - condition : ldap condition used
2881
 *
2882
 * @return array|boolean dn of the user, else false
2883
 * @throws \RuntimeException
2884
 */
2885
 static function searchUserDn($ds, $options = []) {
2886
2887
 $values = [
2888
 'basedn' => '',
2889
 'login_field' => '',
2890
 'search_parameters' => [],
2891
 'user_params' => '',
2892
 'condition' => '',
2893
 'user_dn' => false,
2894
 ];
2895
2896
 foreach ($options as $key => $value) {
2897
 $values[$key] = $value;
2898
 }
2899
2900
 //By default authenticate users by login
2901
 $login_attr = $values['search_parameters']['fields'][self::IDENTIFIER_LOGIN];
2902
 $sync_attr = (isset($values['search_parameters']['fields']['sync_field'])) ?
2903
 $values['search_parameters']['fields']['sync_field'] : null;
2904
2905
 $ldap_parameters = ["dn"];
2906
 foreach ($values['search_parameters']['fields'] as $parameter) {
2907
 $ldap_parameters[] = $parameter;
2908
 }
2909
2910
 //First : if a user dn is provided, look for it in the directory
2911
 //Before trying to find the user using his login_field
2912
 if ($values['user_dn']) {
2913
 $info = self::getUserByDn($ds, $values['user_dn'], $ldap_parameters);
2914
2915
 if ($info) {
2916
 $ret = [
2917
 'dn' => $values['user_dn'],
2918
 $login_attr => $info[$login_attr][0]
2919
 ];
2920
 if ($sync_attr !== null && isset($info[0][$sync_attr])) {
2921
 $ret['sync_field'] = self::getFieldValue($info[0], $sync_attr);
2922
 }
2923
 return $ret;
2924
 }
2925
 }
2926
2927
 // Try a search to find the DN
2928
 $filter_value = $values['user_params']['value'];
2929
 if ($values['login_field'] == 'objectguid' && self::isValidGuid($filter_value)) {
2930
 $filter_value = self::guidToHex($filter_value);
2931
 }
2932
 $filter = "(".$values['login_field']."=".$filter_value.")";
2933
2934
 if (!empty($values['condition'])) {
2935
 $filter = "(& $filter ".$values['condition'].")";
2936
 }
2937
2938
 if ($result = @ldap_search($ds, $values['basedn'], $filter, $ldap_parameters)) {
2939
 //search has been done, let's check for found results
2940
 $info = self::get_entries_clean($ds, $result);
2941
2942
 if (is_array($info) && ($info['count'] == 1)) {
2943
 $ret = [
2944
 'dn' => $info[0]['dn'],
2945
 $login_attr => $info[0][$login_attr][0]
2946
 ];
2947
 if ($sync_attr !== null && isset($info[0][$sync_attr])) {
2948
 $ret['sync_field'] = self::getFieldValue($info[0], $sync_attr);
2949
 }
2950
 return $ret;
2951
 }
2952
 return false;
2953
 }
2954
 throw new \RuntimeException('Something went wrong searching in LDAP directory');
2955
 }
2956
2957
2958
 /**
2959
 * Get an object from LDAP by giving his DN
2960
 *
2961
 * @param resource $ds the active connection to the directory
2962
 * @param string $condition the LDAP filter to use for the search
2963
 * @param string $dn DN of the object
2964
 * @param array $attrs Array of the attributes to retrieve
2965
 * @param boolean $clean (true by default)
2966
 *
2967
 * @return array|boolean false if failed
2968
 */
2969
 static function getObjectByDn($ds, $condition, $dn, $attrs = [], $clean = true) {
2970
 if ($result = @ ldap_read($ds, $dn, $condition, $attrs)) {
2971
 if ($clean) {
2972
 $info = self::get_entries_clean($ds, $result);
2973
 } else {
2974
 $info = ldap_get_entries($ds, $result);
2975
 }
2976
 if (is_array($info) && ($info['count'] == 1)) {
2977
 return $info[0];
2978
 }
2979
 }
2980
2981
 return false;
2982
 }
2983
2984
2985
 /**
2986
 * Get user by domain name
2987
 *
2988
 * @param resource $ds the active connection to the directory
2989
 * @param string $user_dn domain name
2990
 * @param array $attrs attributes
2991
 * @param boolean $clean (true by default)
2992
 *
2993
 * @return array|boolean false if failed
2994
 */
2995
 static function getUserByDn($ds, $user_dn, $attrs, $clean = true) {
2996
 return self::getObjectByDn($ds, "objectClass=*", $user_dn, $attrs, $clean);
2997
 }
2998
2999
 /**
3000
 * Get infos for groups
3001
 *
3002
 * @param resource $ds LDAP link
3003
 * @param string $group_dn dn of the group
3004
 *
3005
 * @return array|boolean group infos if found, else false
3006
 */
3007
 static function getGroupByDn($ds, $group_dn) {
3008
 return self::getObjectByDn($ds, "objectClass=*", $group_dn, ["cn"]);
3009
 }
3010
3011
3012
 /**
3013
 * Manage values stored in session
3014
 *
3015
 * @param array $options Options
3016
 * @param boolean $delete (false by default)
3017
 *
3018
 * @return void
3019
 */
3020
 static function manageValuesInSession($options = [], $delete = false) {
3021
3022
 $fields = ['action', 'authldaps_id', 'basedn', 'begin_date', 'criterias', 'end_date',
3023
 'entities_id', 'interface', 'ldap_filter', 'mode'];
3024
3025
 //If form accessed via modal, do not show expert mode link
3026
 // Manage new value is set : entity or mode
3027
 if (isset($options['entity'])
3028
 || isset($options['mode'])) {
3029
 if (isset($options['_in_modal']) && $options['_in_modal']) {
3030
 //If coming form the helpdesk form : reset all criterias
3031
 $_SESSION['ldap_import']['_in_modal'] = 1;
3032
 $_SESSION['ldap_import']['no_expert_mode'] = 1;
3033
 $_SESSION['ldap_import']['action'] = 'show';
3034
 $_SESSION['ldap_import']['interface'] = self::SIMPLE_INTERFACE;
3035
 $_SESSION['ldap_import']['mode'] = self::ACTION_IMPORT;
3036
 } else {
3037
 $_SESSION['ldap_import']['_in_modal'] = 0;
3038
 $_SESSION['ldap_import']['no_expert_mode'] = 0;
3039
 }
3040
 }
3041
3042
 if (!$delete) {
3043
3044
 if (!isset($_SESSION['ldap_import']['entities_id'])) {
3045
 $options['entities_id'] = $_SESSION['glpiactive_entity'];
3046
 }
3047
3048
 if (isset($options['toprocess'])) {
3049
 $_SESSION['ldap_import']['action'] = 'process';
3050
 }
3051
3052
 if (isset($options['change_directory'])) {
3053
 $options['ldap_filter'] = '';
3054
 }
3055
3056
 if (!isset($_SESSION['ldap_import']['authldaps_id'])) {
3057
 $_SESSION['ldap_import']['authldaps_id'] = NOT_AVAILABLE;
3058
 }
3059
3060
 if ((!Config::canUpdate()
3061
 && !Entity::canUpdate())
3062
 || (!isset($_SESSION['ldap_import']['interface'])
3063
 && !isset($options['interface']))) {
3064
 $options['interface'] = self::SIMPLE_INTERFACE;
3065
 }
3066
3067
 foreach ($fields as $field) {
3068
 if (isset($options[$field])) {
3069
 $_SESSION['ldap_import'][$field] = $options[$field];
3070
 }
3071
 }
3072
 if (isset($_SESSION['ldap_import']['begin_date'])
3073
 && ($_SESSION['ldap_import']['begin_date'] == 'NULL')) {
3074
 $_SESSION['ldap_import']['begin_date'] = '';
3075
 }
3076
 if (isset($_SESSION['ldap_import']['end_date'])
3077
 && ($_SESSION['ldap_import']['end_date'] == 'NULL')) {
3078
 $_SESSION['ldap_import']['end_date'] = '';
3079
 }
3080
 if (!isset($_SESSION['ldap_import']['criterias'])) {
3081
 $_SESSION['ldap_import']['criterias'] = [];
3082
 }
3083
3084
 $authldap = new self();
3085
 //Filter computation
3086
 if ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE) {
3087
 $entity = new Entity();
3088
3089
 if ($entity->getFromDB($_SESSION['ldap_import']['entities_id'])
3090
 && ($entity->getField('authldaps_id') > 0)) {
3091
3092
 $authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
3093
 $_SESSION['ldap_import']['authldaps_id'] = $entity->getField('authldaps_id');
3094
 $_SESSION['ldap_import']['basedn'] = $entity->getField('ldap_dn');
3095
3096
 // No dn specified in entity : use standard one
3097
 if (empty($_SESSION['ldap_import']['basedn'])) {
3098
 $_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
3099
 }
3100
3101
 if ($entity->getField('entity_ldapfilter') != NOT_AVAILABLE) {
3102
 $_SESSION['ldap_import']['entity_filter']
3103
 = $entity->getField('entity_ldapfilter');
3104
 }
3105
3106
 } else {
3107
 if ($_SESSION['ldap_import']['authldaps_id'] == NOT_AVAILABLE
3108
 || !$_SESSION['ldap_import']['authldaps_id']) {
3109
 $_SESSION['ldap_import']['authldaps_id'] = self::getDefault();
3110
 }
3111
3112
 if ($_SESSION['ldap_import']['authldaps_id'] > 0) {
3113
 $authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
3114
 $_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
3115
 }
3116
 }
3117
3118
 if ($_SESSION['ldap_import']['authldaps_id'] > 0) {
3119
 $_SESSION['ldap_import']['ldap_filter'] = self::buildLdapFilter($authldap);
3120
 }
3121
3122
 } else {
3123
 if ($_SESSION['ldap_import']['authldaps_id'] == NOT_AVAILABLE
3124
 || !$_SESSION['ldap_import']['authldaps_id']) {
3125
3126
 $_SESSION['ldap_import']['authldaps_id'] = self::getDefault();
3127
3128
 if ($_SESSION['ldap_import']['authldaps_id'] > 0) {
3129
 $authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
3130
 $_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
3131
 }
3132
 }
3133
 if (!isset($_SESSION['ldap_import']['ldap_filter'])
3134
 || $_SESSION['ldap_import']['ldap_filter'] == '') {
3135
3136
 $authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
3137
 $_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
3138
 $_SESSION['ldap_import']['ldap_filter'] = self::buildLdapFilter($authldap);
3139
 }
3140
 }
3141
 } else { // Unset all values in session
3142
 unset($_SESSION['ldap_import']);
3143
 }
3144
 }
3145
3146
3147
 /**
3148
 * Show import user form
3149
 *
3150
 * @param AuthLDAP $authldap AuthLDAP object
3151
 *
3152
 * @return void
3153
 */
3154
 static function showUserImportForm(AuthLDAP $authldap) {
3155
3156
 //Get data related to entity (directory and ldap filter)
3157
 $authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
3158
 echo "<div class='center'>";
3159
3160
 echo "<form method='post' action='".$_SERVER['PHP_SELF']."'>";
3161
3162
 echo "<table class='tab_cadre_fixe'>";
3163
3164
 echo "<tr><th colspan='4' class='middle'><div class='relative'>";
3165
 echo "<span>" .($_SESSION['ldap_import']['mode']?__('Synchronizing already imported users')
3166
 :__('Import new users'));
3167
3168
 // Expert interface allow user to override configuration.
3169
 // If not coming from the ticket form, then give expert/simple link
3170
 if ((Config::canUpdate()
3171
 || Entity::canUpdate())
3172
 && (!isset($_SESSION['ldap_import']['no_expert_mode'])
3173
 || $_SESSION['ldap_import']['no_expert_mode'] != 1)) {
3174
3175
 echo "</span>&nbsp;<span class='floatright'><a href='".$_SERVER['PHP_SELF']."?action=".
3176
 $_SESSION['ldap_import']['action']."&amp;mode=".$_SESSION['ldap_import']['mode'];
3177
3178
 if ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE) {
3179
 echo "&amp;interface=".self::EXPERT_INTERFACE."'>".__('Expert mode')."</a>";
3180
 } else {
3181
 echo "&amp;interface=".self::SIMPLE_INTERFACE."'>".__('Simple mode')."</a>";
3182
 }
3183
 } else {
3184
 $_SESSION['ldap_import']['interface'] = self::SIMPLE_INTERFACE;
3185
 }
3186
 echo "</span></div>";
3187
 echo "</th></tr>";
3188
3189
 switch ($_SESSION['ldap_import']['interface']) {
3190
 case self::EXPERT_INTERFACE :
3191
 //If more than one directory configured
3192
 //Display dropdown ldap servers
3193
 if (($_SESSION['ldap_import']['authldaps_id'] != NOT_AVAILABLE)
3194
 && ($_SESSION['ldap_import']['authldaps_id'] > 0)) {
3195
3196
 if (self::getNumberOfServers() > 1) {
3197
 $rand = mt_rand();
3198
 echo "<tr class='tab_bg_2'><td><label for='dropdown_authldaps_id$rand'>".__('LDAP directory choice')."</label></td>";
3199
 echo "<td colspan='3'>";
3200
 self::dropdown(['name' => 'authldaps_id',
3201
 'value' => $_SESSION['ldap_import']['authldaps_id'],
3202
 'condition' => ['is_active' => 1],
3203
 'display_emptychoice' => false,
3204
 'rand' => $rand]);
3205
 echo "&nbsp;<input class='submit' type='submit' name='change_directory'
3206
 value=\""._sx('button', 'Change')."\">";
3207
 echo "</td></tr>";
3208
 }
3209
3210
 echo "<tr class='tab_bg_2'><td><label for='basedn'>".__('BaseDN')."</label></td><td colspan='3'>";
3211
 echo "<input type='text' id='basedn' name='basedn' value=\"".$_SESSION['ldap_import']['basedn'].
3212
 "\" size='90' ".(!$_SESSION['ldap_import']['basedn']?"disabled":"").">";
3213
 echo "</td></tr>";
3214
3215
 echo "<tr class='tab_bg_2'><td><label for='ldap_filter'>".__('Search filter for users')."</label></td><td colspan='3'>";
3216
 echo "<input type='text' id='ldap_filter' name='ldap_filter' value=\"".
3217
 $_SESSION['ldap_import']['ldap_filter']."\" size='90'>";
3218
 echo "</td></tr>";
3219
 }
3220
 break;
3221
3222
 //case self::SIMPLE_INTERFACE :
3223
 default :
3224
 if (self::getNumberOfServers() > 1) {
3225
 $rand = mt_rand();
3226
 echo "<tr class='tab_bg_2'><td><label for='dropdown_authldaps_id$rand'>".__('LDAP directory choice')."</label></td>";
3227
 echo "<td colspan='3'>";
3228
 self::dropdown(['name' => 'authldaps_id',
3229
 'value' => $_SESSION['ldap_import']['authldaps_id'],
3230
 'condition' => ['is_active' => 1],
3231
 'display_emptychoice' => false,
3232
 'rand' => $rand]);
3233
 echo "&nbsp;<input class='submit' type='submit' name='change_directory'
3234
 value=\""._sx('button', 'Change')."\">";
3235
 echo "</td></tr>";
3236
 }
3237
3238
 //If multi-entity mode and more than one entity visible
3239
 //else no need to select entity
3240
 if (Session::isMultiEntitiesMode()
3241
 && (count($_SESSION['glpiactiveentities']) > 1)) {
3242
 echo "<tr class='tab_bg_2'><td>".__('Select the desired entity')."</td>".
3243
 "<td colspan='3'>";
3244
 Entity::dropdown(['value' => $_SESSION['ldap_import']['entities_id'],
3245
 'entity' => $_SESSION['glpiactiveentities'],
3246
 'on_change' => 'this.form.submit()']);
3247
 echo "</td></tr>";
3248
 } else {
3249
 //Only one entity is active, store it
3250
 echo "<tr><td><input type='hidden' name='entities_id' value='".
3251
 $_SESSION['glpiactive_entity']."'></td></tr>";
3252
 }
3253
3254
 if ((isset($_SESSION['ldap_import']['begin_date'])
3255
 && !empty($_SESSION['ldap_import']['begin_date']))
3256
 || (isset($_SESSION['ldap_import']['end_date'])
3257
 && !empty($_SESSION['ldap_import']['end_date']))) {
3258
 $enabled = 1;
3259
 } else {
3260
 $enabled = 0;
3261
 }
3262
 Dropdown::showAdvanceDateRestrictionSwitch($enabled);
3263
3264
 echo "<table class='tab_cadre_fixe'>";
3265
3266
 if (($_SESSION['ldap_import']['authldaps_id'] != NOT_AVAILABLE)
3267
 && ($_SESSION['ldap_import']['authldaps_id'] > 0)) {
3268
3269
 $field_counter = 0;
3270
 $fields = ['login_field' => __('Login'),
3271
 'sync_field' => __('Synchronization field') . ' (' . $authldap->fields['sync_field'] . ')',
3272
 'email1_field' => _n('Email', 'Emails', 1),
3273
 'email2_field' => sprintf(__('%1$s %2$s'),
3274
 _n('Email', 'Emails', 1), '2'),
3275
 'email3_field' => sprintf(__('%1$s %2$s'),
3276
 _n('Email', 'Emails', 1), '3'),
3277
 'email4_field' => sprintf(__('%1$s %2$s'),
3278
 _n('Email', 'Emails', 1), '4'),
3279
 'realname_field' => __('Surname'),
3280
 'firstname_field' => __('First name'),
3281
 'phone_field' => _x('ldap', 'Phone'),
3282
 'phone2_field' => __('Phone 2'),
3283
 'mobile_field' => __('Mobile phone'),
3284
 'title_field' => _x('person', 'Title'),
3285
 'category_field' => __('Category'),
3286
 'picture_field' => __('Picture')];
3287
 $available_fields = [];
3288
 foreach ($fields as $field => $label) {
3289
 if (isset($authldap->fields[$field]) && ($authldap->fields[$field] != '')) {
3290
 $available_fields[$field] = $label;
3291
 }
3292
 }
3293
 echo "<tr><th colspan='4'>" . __('Search criteria for users') . "</th></tr>";
3294
 foreach ($available_fields as $field => $label) {
3295
 if ($field_counter == 0) {
3296
 echo "<tr class='tab_bg_1'>";
3297
 }
3298
 echo "<td><label for='criterias$field'>$label</label></td><td>";
3299
 $field_counter++;
3300
 $field_value = '';
3301
 if (isset($_SESSION['ldap_import']['criterias'][$field])) {
3302
 $field_value = Html::entities_deep(Toolbox::unclean_cross_side_scripting_deep(Toolbox::stripslashes_deep($_SESSION['ldap_import']['criterias'][$field])));
3303
 }
3304
 echo "<input type='text' id='criterias$field' name='criterias[$field]' value='$field_value'>";
3305
 echo "</td>";
3306
 if ($field_counter == 2) {
3307
 echo "</tr>";
3308
 $field_counter = 0;
3309
 }
3310
 }
3311
 if ($field_counter > 0) {
3312
 while ($field_counter < 2) {
3313
 echo "<td colspan='2'></td>";
3314
 $field_counter++;
3315
 }
3316
 $field_counter = 0;
3317
 echo "</tr>";
3318
 }
3319
 }
3320
 break;
3321
 }
3322
3323
 if (($_SESSION['ldap_import']['authldaps_id'] != NOT_AVAILABLE)
3324
 && ($_SESSION['ldap_import']['authldaps_id'] > 0)) {
3325
3326
 if ($_SESSION['ldap_import']['authldaps_id']) {
3327
 echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
3328
 echo "<input class='submit' type='submit' name='search' value=\"".
3329
 _sx('button', 'Search')."\">";
3330
 echo "</td></tr>";
3331
 } else {
3332
 echo "<tr class='tab_bg_2'><".
3333
 "td colspan='4' class='center'>".__('No directory selected')."</td></tr>";
3334
 }
3335
3336
 } else {
3337
 echo "<tr class='tab_bg_2'><td colspan='4' class='center'>".
3338
 __('No directory associated to entity: impossible search')."</td></tr>";
3339
 }
3340
 echo "</table>";
3341
 Html::closeForm();
3342
 echo "</div>";
3343
 }
3344
3345
 /**
3346
 * Get number of servers
3347
 *
3348
 * @var DBmysql $DB
3349
 *
3350
 * @return integer
3351
 */
3352
 static function getNumberOfServers() {
3353
 return countElementsInTable('glpi_authldaps', ['is_active' => 1]);
3354
 }
3355
3356
3357
 /**
3358
 * Build LDAP filter
3359
 *
3360
 * @param AuthLDAP $authldap AuthLDAP object
3361
 *
3362
 * @return string
3363
 */
3364
 static function buildLdapFilter(AuthLDAP $authldap) {
3365
 //Build search filter
3366
 $counter = 0;
3367
 $filter = '';
3368
3369
 if (!empty($_SESSION['ldap_import']['criterias'])
3370
 && ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE)) {
3371
3372
 foreach ($_SESSION['ldap_import']['criterias'] as $criteria => $value) {
3373
 if ($value != '') {
3374
 $begin = 0;
3375
 $end = 0;
3376
 if (($length = strlen($value)) > 0) {
3377
 if ($value[0] == '^') {
3378
 $begin = 1;
3379
 }
3380
 if ($value[$length-1] == '$') {
3381
 $end = 1;
3382
 }
3383
 }
3384
 if ($begin || $end) {
3385
 // no Toolbox::substr, to be consistent with strlen result
3386
 $value = substr($value, $begin, $length-$end-$begin);
3387
 }
3388
 $counter++;
3389
 $filter .= '('.$authldap->fields[$criteria].'='.($begin?'':'*').$value.($end?'':'*').')';
3390
 }
3391
 }
3392
 } else {
3393
 $filter = "(".$authldap->getField("login_field")."=*)";
3394
 }
3395
3396
 //If time restriction
3397
 $begin_date = (isset($_SESSION['ldap_import']['begin_date'])
3398
 && !empty($_SESSION['ldap_import']['begin_date'])
3399
 ? $_SESSION['ldap_import']['begin_date'] : null);
3400
 $end_date = (isset($_SESSION['ldap_import']['end_date'])
3401
 && !empty($_SESSION['ldap_import']['end_date'])
3402
 ? $_SESSION['ldap_import']['end_date'] : null);
3403
 $filter .= self::addTimestampRestrictions($begin_date, $end_date);
3404
 $ldap_condition = $authldap->getField('condition');
3405
 //Add entity filter and filter filled in directory's configuration form
3406
 return "(&".(isset($_SESSION['ldap_import']['entity_filter'])
3407
 ?$_SESSION['ldap_import']['entity_filter']
3408
 :'')." $filter $ldap_condition)";
3409
 }
3410
3411
3412
 /**
3413
 * Add timestamp restriction
3414
 *
3415
 * @param string $begin_date datetime begin date to search (NULL if not take into account)
3416
 * @param string $end_date datetime end date to search (NULL if not take into account)
3417
 *
3418
 * @return string
3419
 */
3420
 static function addTimestampRestrictions($begin_date, $end_date) {
3421
3422
 $condition = '';
3423
 //If begin date
3424
 if (!empty($begin_date)) {
3425
 $stampvalue = self::date2ldapTimeStamp($begin_date);
3426
 $condition .= "(modifyTimestamp>=".$stampvalue.")";
3427
 }
3428
 //If end date
3429
 if (!empty($end_date)) {
3430
 $stampvalue = self::date2ldapTimeStamp($end_date);
3431
 $condition .= "(modifyTimestamp<=".$stampvalue.")";
3432
 }
3433
 return $condition;
3434
 }
3435
3436
3437
 /**
3438
 * Search user
3439
 *
3440
 * @param AuthLDAP $authldap AuthLDAP object
3441
 *
3442
 * @return void
3443
 */
3444
 static function searchUser(AuthLDAP $authldap) {
3445
3446
 if (self::connectToServer($authldap->getField('host'), $authldap->getField('port'),
3447
 $authldap->getField('rootdn'),
3448
 Toolbox::sodiumDecrypt($authldap->getField('rootdn_passwd')),
3449
 $authldap->getField('use_tls'),
3450
 $authldap->getField('deref_option'))) {
3451
 self::showLdapUsers();
3452
3453
 } else {
3454
 echo "<div class='center b firstbloc'>".__('Unable to connect to the LDAP directory');
3455
 }
3456
 }
3457
3458
 /**
3459
 * Get default ldap
3460
 *
3461
 * @var DBmysql $DB DB instance
3462
 *
3463
 * @return integer
3464
 */
3465
 static function getDefault() {
3466
 global $DB;
3467
3468
 foreach ($DB->request('glpi_authldaps', ['is_default' => 1, 'is_active' => 1]) as $data) {
3469
 return $data['id'];
3470
 }
3471
 return 0;
3472
 }
3473
3474
 function post_updateItem($history = 1) {
3475
 global $DB;
3476
3477
 if (in_array('is_default', $this->updates) && $this->input["is_default"]==1) {
3478
 $DB->update(
3479
 $this->getTable(),
3480
 ['is_default' => 0],
3481
 ['id' => ['<>', $this->input['id']]]
3482
 );
3483
 }
3484
 }
3485
3486
 function post_addItem() {
3487
 global $DB;
3488
3489
 if (isset($this->fields['is_default']) && $this->fields["is_default"]==1) {
3490
 $DB->update(
3491
 $this->getTable(),
3492
 ['is_default' => 0],
3493
 ['id' => ['<>', $this->fields['id']]]
3494
 );
3495
 }
3496
 }
3497
3498
 function prepareInputForAdd($input) {
3499
3500
 //If it's the first ldap directory then set it as the default directory
3501
 if (!self::getNumberOfServers()) {
3502
 $input['is_default'] = 1;
3503
 }
3504
3505
 if (isset($input["rootdn_passwd"]) && !empty($input["rootdn_passwd"])) {
3506
 $input["rootdn_passwd"] = Toolbox::sodiumEncrypt($input["rootdn_passwd"]);
3507
 }
3508
3509
 return $input;
3510
 }
3511
3512
3513
 /**
3514
 * Get LDAP deleted user action options.
3515
 *
3516
 * @return array
3517
 */
3518
 static function getLdapDeletedUserActionOptions() {
3519
3520
 return [
3521
 self::DELETED_USER_PRESERVE => __('Preserve'),
3522
 self::DELETED_USER_DELETE => __('Put in trashbin'),
3523
 self::DELETED_USER_WITHDRAWDYNINFO => __('Withdraw dynamic authorizations and groups'),
3524
 self::DELETED_USER_DISABLE => __('Disable'),
3525
 self::DELETED_USER_DISABLEANDWITHDRAWDYNINFO => __('Disable').' + '.__('Withdraw dynamic authorizations and groups'),
3526
 ];
3527
 }
3528
3529
 /**
3530
 * Builds deleted actions dropdown
3531
 *
3532
 * @param integer $value (default 0)
3533
 *
3534
 * @return string
3535
 */
3536
 static function dropdownUserDeletedActions($value = 0) {
3537
3538
 $options = self::getLdapDeletedUserActionOptions();
3539
 asort($options);
3540
 return Dropdown::showFromArray('user_deleted_ldap', $options, ['value' => $value]);
3541
 }
3542
3543
3544
 /**
3545
 * Return all the ldap servers where email field is configured
3546
 *
3547
 * @return array of LDAP server's ID
3548
 */
3549
 static function getServersWithImportByEmailActive() {
3550
 global $DB;
3551
3552
 $ldaps = [];
3553
 // Always get default first
3554
3555
 $iterator = $DB->request([
3556
 'SELECT' => ['id'],
3557
 'FROM' => 'glpi_authldaps',
3558
 'WHERE' => [
3559
 'is_active' => 1,
3560
 'OR' => [
3561
 'email1_field' => ['<>', ''],
3562
 'email2_field' => ['<>', ''],
3563
 'email3_field' => ['<>', ''],
3564
 'email4_field' => ['<>', '']
3565
 ]
3566
 ],
3567
 'ORDER' => ['is_default DESC']
3568
 ]);
3569
 while ($data = $iterator->next()) {
3570
 $ldaps[] = $data['id'];
3571
 }
3572
 return $ldaps;
3573
 }
3574
3575
3576
 /**
3577
 * Show date restriction form
3578
 *
3579
 * @param array $options Options
3580
 *
3581
 * @return void
3582
 */
3583
 static function showDateRestrictionForm($options = []) {
3584
3585
 echo "<table class='tab_cadre_fixe'>";
3586
 echo "<tr class='tab_bg_2'>";
3587
3588
 $enabled = (isset($options['enabled'])?$options['enabled']:false);
3589
 if (!$enabled) {
3590
 echo "<td colspan='4' class='center'>";
3591
 echo "<a href='#' onClick='activateRestriction()'>".__('Enable filtering by date')."</a>";
3592
 echo "</td></tr>";
3593
 }
3594
 if ($enabled) {
3595
 echo "<td>".__('View updated users')."</td>";
3596
 echo "<td>".__('from')."</td>";
3597
 echo "<td>";
3598
 $begin_date = (isset($_SESSION['ldap_import']['begin_date'])
3599
 ?$_SESSION['ldap_import']['begin_date'] :'');
3600
 Html::showDateTimeField("begin_date", ['value' => $begin_date]);
3601
 echo "</td>";
3602
 echo "<td>".__('to')."</td>";
3603
 echo "<td>";
3604
 $end_date = (isset($_SESSION['ldap_import']['end_date'])
3605
 ?$_SESSION['ldap_import']['end_date']
3606
 :date('Y-m-d H:i:s', time()-DAY_TIMESTAMP));
3607
 Html::showDateTimeField("end_date", ['value' => $end_date]);
3608
 echo "</td></tr>";
3609
 echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
3610
 echo "<a href='#' onClick='deactivateRestriction()'>".__('Disable filtering by date')."</a>";
3611
 echo "</td></tr>";
3612
 }
3613
 echo "</table>";
3614
 }
3615
3616
 function cleanDBonPurge() {
3617
 Rule::cleanForItemCriteria($this, 'LDAP_SERVER');
3618
 }
3619
3620
 function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
3621
3622
 if (!$withtemplate
3623
 && $item->can($item->getField('id'), READ)) {
3624
 $ong = [];
3625
 $ong[1] = _sx('button', 'Test'); // test connexion
3626
 $ong[2] = User::getTypeName(Session::getPluralNumber());
3627
 $ong[3] = Group::getTypeName(Session::getPluralNumber());
3628
 // TODO clean fields entity_XXX if not used
3629
 // $ong[4] = Entity::getTypeName(1); // params for entity config
3630
 $ong[5] = __('Advanced information'); // params for entity advanced config
3631
 $ong[6] = _n('Replicate', 'Replicates', Session::getPluralNumber());
3632
3633
 return $ong;
3634
 }
3635
 return '';
3636
 }
3637
3638
 /**
3639
 * Choose wich form to show
3640
 *
3641
 * @param CommonGLPI $item Item instance
3642
 * @param integer $tabnum Tab number
3643
 * @param integer $withtemplate Unused
3644
 *
3645
 * @return boolean (TRUE)
3646
 */
3647
 static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
3648
3649
 switch ($tabnum) {
3650
 case 1 :
3651
 $item->showFormTestLDAP();
3652
 break;
3653
3654
 case 2 :
3655
 $item->showFormUserConfig();
3656
 break;
3657
3658
 case 3 :
3659
 $item->showFormGroupsConfig();
3660
 break;
3661
3662
 case 4 :
3663
 $item->showFormEntityConfig();
3664
 break;
3665
3666
 case 5 :
3667
 $item->showFormAdvancedConfig();
3668
 break;
3669
3670
 case 6 :
3671
 $item->showFormReplicatesConfig();
3672
 break;
3673
 }
3674
 return true;
3675
 }
3676
3677
3678
 /**
3679
 * Get ldap query results and clean them at the same time
3680
 *
3681
 * @param resource $link link to the directory connection
3682
 * @param array $result the query results
3683
 *
3684
 * @return array which contains ldap query results
3685
 */
3686
 static function get_entries_clean($link, $result) {
3687
 return ldap_get_entries($link, $result);
3688
 }
3689
3690
3691
 /**
3692
 * Get all replicate servers for a master one
3693
 *
3694
 * @param integer $master_id master ldap server ID
3695
 *
3696
 * @return array of the replicate servers
3697
 */
3698
 static function getAllReplicateForAMaster($master_id) {
3699
 global $DB;
3700
3701
 $replicates = [];
3702
 $criteria = ['FIELDS' => ['id', 'host', 'port'],
3703
 'FROM' => 'glpi_authldapreplicates',
3704
 'WHERE' => ['authldaps_id' => $master_id]
3705
 ];
3706
 foreach ($DB->request($criteria) as $replicate) {
3707
 $replicates[] = ["id" => $replicate["id"],
3708
 "host" => $replicate["host"],
3709
 "port" => $replicate["port"]
3710
 ];
3711
 }
3712
 return $replicates;
3713
 }
3714
3715
 /**
3716
 * Check if ldap results can be paged or not
3717
 * This functionality is available for PHP 5.4 and higher
3718
 *
3719
 * @since 0.84
3720
 *
3721
 * @param object $config_ldap LDAP configuration
3722
 * @param boolean $check_config_value Whether to check config values
3723
 *
3724
 * @return boolean true if maxPageSize can be used, false otherwise
3725
 */
3726
 static function isLdapPageSizeAvailable($config_ldap, $check_config_value = true) {
3727
 return (extension_loaded('ldap') && (!$check_config_value
3728
 || ($check_config_value && $config_ldap->fields['can_support_pagesize'])));
3729
 }
3730
3731
 /**
3732
 * Does LDAP user already exists in the database?
3733
 *
3734
 * @param string $name User login/name
3735
 * @param integer $authldaps_id LDAP authentication server ID
3736
 * @param ?string $sync Sync field
3737
 *
3738
 * @return false|User
3739
 */
3740
 public function getLdapExistingUser($name, $authldaps_id, $sync = null) {
3741
 global $DB;
3742
 $user = new User();
3743
3744
 if ($sync !== null && $user->getFromDBbySyncField($sync)) {
3745
 return $user;
3746
 }
3747
3748
 if ($user->getFromDBbyNameAndAuth($DB->escape($name), Auth::LDAP, $authldaps_id)) {
3749
 return $user;
3750
 }
3751
3752
 return false;
3753
 }
3754
3755
 /**
3756
 * Is synchronisation field used for current server
3757
 *
3758
 * @return boolean
3759
 */
3760
 public function isSyncFieldUsed() {
3761
 $count = countElementsInTable(
3762
 'glpi_users',
3763
 [
3764
 'auths_id' => $this->getID(),
3765
 'NOT' => ['sync_field' => null]
3766
 ]
3767
 );
3768
 return $count > 0;
3769
 }
3770
3771
 /**
3772
 * Get a LDAP field value
3773
 *
3774
 * @param array $infos LDAP entry infos
3775
 * @param string $field Field name to retrieve
3776
 *
3777
 * @return string
3778
 */
3779
 public static function getFieldValue($infos, $field) {
3780
 $value = null;
3781
 if (is_array($infos[$field])) {
3782
 $value = $infos[$field][0];
3783
 } else {
3784
 $value = $infos[$field];
3785
 }
3786
 if ($field != 'objectguid') {
3787
 return $value;
3788
 }
3789
3790
 //handle special objectguid from AD directories
3791
 try {
3792
 //prevent double encoding
3793
 if (!self::isValidGuid($value)) {
3794
 $value = self::guidToString($value);
3795
 if (!self::isValidGuid($value)) {
3796
 throw new \RuntimeException('Not an objectguid!');
3797
 }
3798
 }
3799
 } catch (\Exception $e) {
3800
 //well... this is not an objectguid apparently
3801
 $value = $infos[$field];
3802
 }
3803
3804
 return $value;
3805
 }
3806
3807
 /**
3808
 * Converts a string representation of an objectguid to hexadecimal
3809
 * Used to build filters
3810
 *
3811
 * @param string $guid_str String representation
3812
 *
3813
 * @return string
3814
 */
3815
 public static function guidToHex($guid_str) {
3816
 $str_g = explode('-', $guid_str);
3817
3818
 $str_g[0] = strrev($str_g[0]);
3819
 $str_g[1] = strrev($str_g[1]);
3820
 $str_g[2] = strrev($str_g[2]);
3821
3822
 $guid_hex = '\\';
3823
 $strrev = 0;
3824
 foreach ($str_g as $str) {
3825
 for ($i = 0; $i < strlen($str)+2; $i++) {
3826
 if ($strrev < 3) {
3827
 $guid_hex .= strrev(substr($str, 0, 2)).'\\';
3828
 } else {
3829
 $guid_hex .= substr($str, 0, 2).'\\';
3830
 }
3831
 $str = substr($str, 2);
3832
 }
3833
 if ($strrev < 3) {
3834
 $guid_hex .= strrev($str);
3835
 } else {
3836
 $guid_hex .= $str;
3837
 }
3838
 $strrev++;
3839
 }
3840
 return $guid_hex;
3841
 }
3842
3843
 /**
3844
 * Converts binary objectguid to string representation
3845
 *
3846
 * @param mixed $guid_bin Binary objectguid from AD
3847
 *
3848
 * @return string
3849
 */
3850
 public static function guidToString($guid_bin) {
3851
 $guid_hex = unpack("H*hex", $guid_bin);
3852
 $hex = $guid_hex["hex"];
3853
3854
 $hex1 = substr($hex, -26, 2) . substr($hex, -28, 2) . substr($hex, -30, 2) . substr($hex, -32, 2);
3855
 $hex2 = substr($hex, -22, 2) . substr($hex, -24, 2);
3856
 $hex3 = substr($hex, -18, 2) . substr($hex, -20, 2);
3857
 $hex4 = substr($hex, -16, 4);
3858
 $hex5 = substr($hex, -12, 12);
3859
3860
 $guid_str = $hex1 . "-" . $hex2 . "-" . $hex3 . "-" . $hex4 . "-" . $hex5;
3861
 return $guid_str;
3862
 }
3863
3864
 /**
3865
 * Check if text representation of an objectguid is valid
3866
 *
3867
 * @param string $guid_str String representation
3868
 *
3869
 * @return boolean
3870
 */
3871
 public static function isValidGuid($guid_str) {
3872
 return (bool) preg_match('/^([0-9a-fA-F]){8}(-([0-9a-fA-F]){4}){3}-([0-9a-fA-F]){12}$/', $guid_str);
3873
 }
3874
3875
 /**
3876
 * Get the list of LDAP users to add/synchronize
3877
 * When importing, already existing users will be filtered
3878
 *
3879
 * @param array $values possible options:
3880
 * - authldaps_id ID of the server to use
3881
 * - mode user to synchronise or add?
3882
 * - ldap_filter ldap filter to use
3883
 * - basedn force basedn (default authldaps_id one)
3884
 * - order display order
3885
 * - begin_date begin date to time limit
3886
 * - end_date end date to time limit
3887
 * - script true if called by an external script
3888
 * @param array $results result stats
3889
 * @param boolean $limitexceeded limit exceeded exception
3890
 *
3891
 * @return array
3892
 */
3893
 public static function getUsers($values, &$results, &$limitexceeded) {
3894
 $users = [];
3895
 $ldap_users = self::getAllUsers($values, $results, $limitexceeded);
3896
3897
 $config_ldap = new AuthLDAP();
3898
 $config_ldap->getFromDB($values['authldaps_id']);
3899
3900
 if (!is_array($ldap_users) || count($ldap_users) == 0) {
3901
 return $users;
3902
 }
3903
3904
 foreach ($ldap_users as $userinfos) {
3905
 $user_to_add = [];
3906
 $user = new User();
3907
3908
 $user_sync_field = null;
3909
 if ($config_ldap->isSyncFieldEnabled()) {
3910
 $sync_field = $config_ldap->fields['sync_field'];
3911
 if (isset($userinfos[$sync_field])) {
3912
 $user_sync_field = self::getFieldValue($userinfos, $sync_field);
3913
 }
3914
 }
3915
3916
 $user = $config_ldap->getLdapExistingUser($userinfos['user'], $values['authldaps_id'],
3917
 $user_sync_field);
3918
 if (isset($_SESSION['ldap_import']) && !$_SESSION['ldap_import']['mode'] && $user) {
3919
 continue;
3920
 }
3921
 $user_to_add['link'] = $userinfos["user"];
3922
 if (isset($userinfos['id']) && User::canView()) {
3923
 $user_to_add['id'] = $userinfos['id'];
3924
 $user_to_add['name'] = $user->fields['name'];
3925
 $user_to_add['link'] = Toolbox::getItemTypeFormURL('User').'?id='.$userinfos['id'];
3926
 }
3927
3928
 $user_to_add['stamp'] = (isset($userinfos["timestamp"])) ? $userinfos["timestamp"] : '';
3929
 $user_to_add['date_sync'] = (isset($userinfos["date_sync"])) ? $userinfos["date_sync"] : '';
3930
3931
 $user_to_add['uid'] = $userinfos['user'];
3932
 if ($config_ldap->isSyncFieldEnabled()) {
3933
 if (isset($userinfos[$sync_field])) {
3934
 $user_to_add['uid'] = self::getFieldValue($userinfos, $sync_field);
3935
 }
3936
3937
 $field_for_sync = $config_ldap->getLdapIdentifierToUse();
3938
 if (isset($userinfos[$field_for_sync])) {
3939
 $user_to_add['sync_field'] = $userinfos[$field_for_sync];
3940
 }
3941
 }
3942
3943
 $users[] = $user_to_add;
3944
 }
3945
3946
 return $users;
3947
 }
3948
}
3949
Top Articles
Latest Posts
Article information

Author: Aracelis Kilback

Last Updated: 25/06/2023

Views: 6138

Rating: 4.3 / 5 (64 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Aracelis Kilback

Birthday: 1994-11-22

Address: Apt. 895 30151 Green Plain, Lake Mariela, RI 98141

Phone: +5992291857476

Job: Legal Officer

Hobby: LARPing, role-playing games, Slacklining, Reading, Inline skating, Brazilian jiu-jitsu, Dance

Introduction: My name is Aracelis Kilback, I am a nice, gentle, agreeable, joyous, attractive, combative, gifted person who loves writing and wants to share my knowledge and understanding with you.