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 " / "; | ||
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'> "; | ||
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'> " | ||
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'> <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 \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 | |||
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')."'> ". | ||
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 | |||
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> </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 | |||
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 | |||
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 " ".__('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 | |||
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 | |||
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 | |||
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> <span class='floatright'><a href='".$_SERVER['PHP_SELF']."?action=". | ||
3176 | $_SESSION['ldap_import']['action']."&mode=".$_SESSION['ldap_import']['mode']; | ||
3177 | |||
3178 | if ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE) { | ||
3179 | echo "&interface=".self::EXPERT_INTERFACE."'>".__('Expert mode')."</a>"; | ||
3180 | } else { | ||
3181 | echo "&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 " <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 " <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 |
Issues in authldap.class.php - All Issues - Inspection of "Fix dbversion when migration from < 9.2 fails" - glpi-project/glpi (2023)
Top Articles
Understanding Evidence-Based Practice in Nursing + 10 Examples
Strategies For Successful Reading Comprehension | UoPeople
8 Best Water Softener Companies: Best Guide in 2022
Best Well Water Fitration System 2022 (Don't Be Fooled)
Warm-Up Activities For New Classes | OUP
Leidenfrost-effect: meer dan zwevende druppels | the Quantum Universe
Netflix: Die besten Serien nach IMDb Bewertungen – Über Doku, Comedy und Crime
Latest Posts
How to Use Sonar to Find Hard Bottoms
Holiday Inn Hamburg - Hafencity, an IHG Hotel Bewertungen, Angebote & Fotos 2023 - Expedia.at
How to watch the Cardinals on Bally Sports Midwest
REPSE, ICSOE Y SISUB, todo lo que debes saber. - Conciencia colectiva
Guía esencial de registro: REPSE, ICSOE y SISUB 2022 - Gestión de Capital Humano y Recursos Humanos | CONSOLIDÉ ® ¡Contáctenos!
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.