3948 lines
147 KiB
PHP
3948 lines
147 KiB
PHP
<?php
|
|
/**
|
|
* ---------------------------------------------------------------------
|
|
* GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2015-2020 Teclib' and contributors.
|
|
*
|
|
* http://glpi-project.org
|
|
*
|
|
* based on GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This file is part of GLPI.
|
|
*
|
|
* GLPI is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GLPI is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GLPI. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Class used to manage Auth LDAP config
|
|
*/
|
|
class AuthLDAP extends CommonDBTM {
|
|
|
|
const SIMPLE_INTERFACE = 'simple';
|
|
const EXPERT_INTERFACE = 'expert';
|
|
|
|
const ACTION_IMPORT = 0;
|
|
const ACTION_SYNCHRONIZE = 1;
|
|
const ACTION_ALL = 2;
|
|
|
|
const USER_IMPORTED = 0;
|
|
const USER_SYNCHRONIZED = 1;
|
|
const USER_DELETED_LDAP = 2;
|
|
|
|
//Import user by giving his login
|
|
const IDENTIFIER_LOGIN = 'login';
|
|
|
|
//Import user by giving his email
|
|
const IDENTIFIER_EMAIL = 'email';
|
|
|
|
const GROUP_SEARCH_USER = 0;
|
|
const GROUP_SEARCH_GROUP = 1;
|
|
const GROUP_SEARCH_BOTH = 2;
|
|
|
|
/**
|
|
* Deleted user strategy: preserve user.
|
|
* @var integer
|
|
*/
|
|
const DELETED_USER_PRESERVE = 0;
|
|
|
|
/**
|
|
* Deleted user strategy: put user in trashbin.
|
|
* @var integer
|
|
*/
|
|
const DELETED_USER_DELETE = 1;
|
|
|
|
/**
|
|
* Deleted user strategy: withdraw dynamic authorizations and groups.
|
|
* @var integer
|
|
*/
|
|
const DELETED_USER_WITHDRAWDYNINFO = 2;
|
|
|
|
/**
|
|
* Deleted user strategy: disable user.
|
|
* @var integer
|
|
*/
|
|
const DELETED_USER_DISABLE = 3;
|
|
|
|
/**
|
|
* Deleted user strategy: disable user and withdraw dynamic authorizations and groups.
|
|
* @var integer
|
|
*/
|
|
const DELETED_USER_DISABLEANDWITHDRAWDYNINFO = 4;
|
|
|
|
// From CommonDBTM
|
|
public $dohistory = true;
|
|
|
|
static $rightname = 'config';
|
|
|
|
//connection caching stuff
|
|
static $conn_cache = [];
|
|
|
|
static $undisclosedFields = [
|
|
'rootdn_passwd',
|
|
];
|
|
|
|
static function getTypeName($nb = 0) {
|
|
return _n('LDAP directory', 'LDAP directories', $nb);
|
|
}
|
|
|
|
static function canCreate() {
|
|
return static::canUpdate();
|
|
}
|
|
|
|
static function canPurge() {
|
|
return static::canUpdate();
|
|
}
|
|
|
|
function post_getEmpty() {
|
|
|
|
$this->fields['port'] = '389';
|
|
$this->fields['condition'] = '';
|
|
$this->fields['login_field'] = 'uid';
|
|
$this->fields['sync_field'] = null;
|
|
$this->fields['use_tls'] = 0;
|
|
$this->fields['group_field'] = '';
|
|
$this->fields['group_condition'] = '';
|
|
$this->fields['group_search_type'] = self::GROUP_SEARCH_USER;
|
|
$this->fields['group_member_field'] = '';
|
|
$this->fields['email1_field'] = 'mail';
|
|
$this->fields['email2_field'] = '';
|
|
$this->fields['email3_field'] = '';
|
|
$this->fields['email4_field'] = '';
|
|
$this->fields['realname_field'] = 'sn';
|
|
$this->fields['firstname_field'] = 'givenname';
|
|
$this->fields['phone_field'] = 'telephonenumber';
|
|
$this->fields['phone2_field'] = '';
|
|
$this->fields['mobile_field'] = '';
|
|
$this->fields['registration_number_field'] = '';
|
|
$this->fields['comment_field'] = '';
|
|
$this->fields['title_field'] = '';
|
|
$this->fields['use_dn'] = 0;
|
|
$this->fields['picture_field'] = '';
|
|
$this->fields['responsible_field'] = '';
|
|
}
|
|
|
|
|
|
/**
|
|
* Preconfig datas for standard system
|
|
*
|
|
* @param string $type type of standard system : AD
|
|
*
|
|
* @return void
|
|
*/
|
|
function preconfig($type) {
|
|
|
|
switch ($type) {
|
|
case 'AD' :
|
|
$this->fields['port'] = "389";
|
|
$this->fields['condition']
|
|
= '(&(objectClass=user)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))';
|
|
$this->fields['login_field'] = 'samaccountname';
|
|
$this->fields['sync_field'] = 'objectguid';
|
|
$this->fields['use_tls'] = 0;
|
|
$this->fields['group_field'] = 'memberof';
|
|
$this->fields['group_condition']
|
|
= '(&(objectClass=user)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))';
|
|
$this->fields['group_search_type'] = self::GROUP_SEARCH_USER;
|
|
$this->fields['group_member_field'] = '';
|
|
$this->fields['email1_field'] = 'mail';
|
|
$this->fields['email2_field'] = '';
|
|
$this->fields['email3_field'] = '';
|
|
$this->fields['email4_field'] = '';
|
|
$this->fields['realname_field'] = 'sn';
|
|
$this->fields['firstname_field'] = 'givenname';
|
|
$this->fields['phone_field'] = 'telephonenumber';
|
|
$this->fields['phone2_field'] = 'othertelephone';
|
|
$this->fields['mobile_field'] = 'mobile';
|
|
$this->fields['registration_number_field'] = 'employeenumber';
|
|
$this->fields['comment_field'] = 'info';
|
|
$this->fields['title_field'] = 'title';
|
|
$this->fields['entity_field'] = 'ou';
|
|
$this->fields['entity_condition'] = '(objectclass=organizationalUnit)';
|
|
$this->fields['use_dn'] = 1;
|
|
$this->fields['can_support_pagesize'] = 1;
|
|
$this->fields['pagesize'] = '1000';
|
|
$this->fields['picture_field'] = '';
|
|
$this->fields['responsible_field'] = 'manager';
|
|
break;
|
|
|
|
default:
|
|
$this->post_getEmpty();
|
|
}
|
|
}
|
|
|
|
function prepareInputForUpdate($input) {
|
|
|
|
if (isset($input["rootdn_passwd"])) {
|
|
if (empty($input["rootdn_passwd"])) {
|
|
unset($input["rootdn_passwd"]);
|
|
} else {
|
|
$input["rootdn_passwd"] = Toolbox::sodiumEncrypt(stripslashes($input["rootdn_passwd"]));
|
|
}
|
|
}
|
|
|
|
if (isset($input["_blank_passwd"]) && $input["_blank_passwd"]) {
|
|
$input['rootdn_passwd'] = '';
|
|
}
|
|
|
|
// Set attributes in lower case
|
|
if (count($input)) {
|
|
foreach ($input as $key => $val) {
|
|
if (preg_match('/_field$/', $key)) {
|
|
$input[$key] = Toolbox::strtolower($val);
|
|
}
|
|
}
|
|
}
|
|
|
|
//do not permit to override sync_field
|
|
if ($this->isSyncFieldEnabled()
|
|
&& isset($input['sync_field'])
|
|
&& $this->isSyncFieldUsed()
|
|
) {
|
|
if ($input['sync_field'] == $this->fields['sync_field']) {
|
|
unset($input['sync_field']);
|
|
} else {
|
|
Session::addMessageAfterRedirect(
|
|
__('Synchronization field cannot be changed once in use.'),
|
|
false,
|
|
ERROR
|
|
);
|
|
return false;
|
|
};
|
|
}
|
|
return $input;
|
|
}
|
|
|
|
static function getSpecificValueToDisplay($field, $values, array $options = []) {
|
|
|
|
if (!is_array($values)) {
|
|
$values = [$field => $values];
|
|
}
|
|
switch ($field) {
|
|
case 'group_search_type' :
|
|
return self::getGroupSearchTypeName($values[$field]);
|
|
}
|
|
return parent::getSpecificValueToDisplay($field, $values, $options);
|
|
}
|
|
|
|
static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) {
|
|
|
|
if (!is_array($values)) {
|
|
$values = [$field => $values];
|
|
}
|
|
$options['display'] = false;
|
|
switch ($field) {
|
|
case 'group_search_type' :
|
|
$options['value'] = $values[$field];
|
|
$options['name'] = $name;
|
|
return self::dropdownGroupSearchType($options);
|
|
}
|
|
return parent::getSpecificValueToSelect($field, $name, $values, $options);
|
|
}
|
|
|
|
static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, array $ids) {
|
|
$input = $ma->getInput();
|
|
|
|
switch ($ma->getAction()) {
|
|
case 'import_group' :
|
|
$group = new Group;
|
|
if (!Session::haveRight("user", User::UPDATEAUTHENT)
|
|
|| !$group->canGlobal(UPDATE)) {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_NORIGHT);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
|
|
return;
|
|
}
|
|
foreach ($ids as $id) {
|
|
if (isset($input["dn"][$id])) {
|
|
$group_dn = $input["dn"][$id];
|
|
if (isset($input["ldap_import_entities"][$id])) {
|
|
$entity = $input["ldap_import_entities"][$id];
|
|
} else {
|
|
$entity = $_SESSION["glpiactive_entity"];
|
|
}
|
|
// Is recursive is in the main form and thus, don't pass through
|
|
// zero_on_empty mechanism inside massive action form ...
|
|
$is_recursive = (empty($input['ldap_import_recursive'][$id]) ? 0 : 1);
|
|
$options = ['authldaps_id' => $_SESSION['ldap_server'],
|
|
'entities_id' => $entity,
|
|
'is_recursive' => $is_recursive,
|
|
'type' => $input['ldap_import_type'][$id]];
|
|
if (AuthLDAP::ldapImportGroup($group_dn, $options)) {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION, $group_dn));
|
|
}
|
|
}
|
|
// Clean history as id does not correspond to group
|
|
$_SESSION['glpimassiveactionselected'] = [];
|
|
}
|
|
return;
|
|
|
|
case 'import' :
|
|
case 'sync' :
|
|
if (!Session::haveRight("user", User::IMPORTEXTAUTHUSERS)) {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_NORIGHT);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
|
|
return;
|
|
}
|
|
foreach ($ids as $id) {
|
|
if (AuthLDAP::ldapImportUserByServerId(['method' => AuthLDAP::IDENTIFIER_LOGIN,
|
|
'value' => $id],
|
|
$_SESSION['ldap_import']['mode'],
|
|
$_SESSION['ldap_import']['authldaps_id'],
|
|
true)) {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION, $id));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
|
|
}
|
|
|
|
/**
|
|
* Print the auth ldap form
|
|
*
|
|
* @param integer $ID ID of the item
|
|
* @param array $options Options
|
|
* - target for the form
|
|
*
|
|
* @return void (display)
|
|
*/
|
|
function showForm($ID, $options = []) {
|
|
|
|
if (!Config::canUpdate()) {
|
|
return false;
|
|
}
|
|
if (empty($ID)) {
|
|
$this->getEmpty();
|
|
if (isset($options['preconfig'])) {
|
|
$this->preconfig($options['preconfig']);
|
|
}
|
|
} else {
|
|
$this->getFromDB($ID);
|
|
}
|
|
|
|
if (Toolbox::canUseLdap()) {
|
|
$this->showFormHeader($options);
|
|
if (empty($ID)) {
|
|
$target = $this->getFormURL();
|
|
echo "<tr class='tab_bg_2'><td>".__('Preconfiguration')."</td> ";
|
|
echo "<td colspan='3'>";
|
|
echo "<a href='$target?preconfig=AD'>".__('Active Directory')."</a>";
|
|
echo " / ";
|
|
echo "<a href='$target?preconfig=default'>".__('Default values');
|
|
echo "</a></td></tr>";
|
|
}
|
|
echo "<tr class='tab_bg_1'><td><label for='name'>" . __('Name') . "</label></td>";
|
|
echo "<td><input type='text' id='name' name='name' value='". $this->fields["name"] ."'></td>";
|
|
if ($ID > 0) {
|
|
echo "<td>".__('Last update')."</td><td>".Html::convDateTime($this->fields["date_mod"]);
|
|
} else {
|
|
echo "<td colspan='2'> ";
|
|
}
|
|
echo "</td></tr>";
|
|
|
|
$defaultrand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='dropdown_is_default$defaultrand'>" . __('Default server') . "</label></td>";
|
|
echo "<td>";
|
|
Dropdown::showYesNo('is_default', $this->fields['is_default'], -1, ['rand' => $defaultrand]);
|
|
echo "</td>";
|
|
$activerand = mt_rand();
|
|
echo "<td><label for='dropdown_is_active$activerand'>" . __('Active'). "</label></td>";
|
|
echo "<td>";
|
|
Dropdown::showYesNo('is_active', $this->fields['is_active'], -1, ['rand' => $activerand]);
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for='host'>" . __('Server') . "</label></td>";
|
|
echo "<td><input type='text' id='host' name='host' value='" . $this->fields["host"] . "'></td>";
|
|
echo "<td><label for='port'>" . __('Port (default=389)') . "</label></td>";
|
|
echo "<td><input id='port' type='text' id='port' name='port' value='".$this->fields["port"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for='condition'>" . __('Connection filter') . "</label></td>";
|
|
echo "<td colspan='3'>";
|
|
echo "<textarea cols='100' rows='1' id='condition' name='condition'>".$this->fields["condition"];
|
|
echo "</textarea>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for='basedn'>" . __('BaseDN') . "</label></td>";
|
|
echo "<td colspan='3'>";
|
|
echo "<input type='text' id='basedn' name='basedn' size='100' value=\"".$this->fields["basedn"]."\">";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for='rootdn'>" . __('RootDN (for non anonymous binds)') . "</label></td>";
|
|
echo "<td colspan='3'><input type='text' name='rootdn' id='rootdn' size='100' value=\"".
|
|
$this->fields["rootdn"]."\">";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for='rootdn_passwd'>" .
|
|
__('Password (for non-anonymous binds)') . "</label></td>";
|
|
echo "<td><input type='password' id='rootdn_passwd' name='rootdn_passwd' value='' autocomplete='new-password'>";
|
|
if ($ID) {
|
|
echo "<input type='checkbox' name='_blank_passwd' id='_blank_passwd'> "
|
|
. "<label for='_blank_passwd'>" . __('Clear') . "</label>";
|
|
}
|
|
echo "</td>";
|
|
echo "<td rowspan='3'><label for='comment'>".__('Comments')."</label></td>";
|
|
echo "<td rowspan='3' class='middle'>";
|
|
echo "<textarea cols='40' rows='4' name='comment' id='comment'>".$this->fields["comment"]."</textarea>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='login_field'>" . __('Login field') . "</label></td>";
|
|
echo "<td><input type='text' id='login_field' name='login_field' value='".$this->fields["login_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
$info_message = __s('Synchronization field cannot be changed once in use.');
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='sync_field'>" . __('Synchronization field') . "<i class='pointer fa fa-info' title='$info_message'></i></td>";
|
|
echo "<td><input type='text' id='sync_field' name='sync_field' value='{$this->fields["sync_field"]}' title='$info_message'";
|
|
if ($this->isSyncFieldEnabled() && $this->isSyncFieldUsed()) {
|
|
echo " disabled='disabled'";
|
|
}
|
|
echo ">";
|
|
echo "</td></tr>";
|
|
|
|
//Fill fields when using preconfiguration models
|
|
if (!$ID) {
|
|
$hidden_fields = ['comment_field', 'email1_field', 'email2_field',
|
|
'email3_field', 'email4_field', 'entity_condition',
|
|
'entity_field', 'firstname_field', 'group_condition',
|
|
'group_field', 'group_member_field', 'group_search_type',
|
|
'mobile_field', 'phone_field', 'phone2_field',
|
|
'realname_field', 'registration_number_field', 'title_field',
|
|
'use_dn', 'use_tls', 'responsible_field'];
|
|
|
|
foreach ($hidden_fields as $hidden_field) {
|
|
echo "<input type='hidden' name='$hidden_field' value='".
|
|
$this->fields[$hidden_field]."'>";
|
|
}
|
|
}
|
|
|
|
echo "</td></tr>";
|
|
|
|
$this->showFormButtons($options);
|
|
|
|
} else {
|
|
echo "<div class='center'> <table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='2'>" . self::getTypeName(1) . "</th></tr>";
|
|
echo "<tr class='tab_bg_2'><td class='center'>";
|
|
echo "<p class='red'>".sprintf(__('%s extension is missing'), 'LDAP')."</p>";
|
|
echo "<p>".__('Impossible to use LDAP as external source of connection')."</p>".
|
|
"</td></tr></table>";
|
|
|
|
echo "<p><strong>".GLPINetwork::getErrorMessage()."</strong></p>";
|
|
echo "</div>";
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show advanced config form
|
|
*
|
|
* @return void
|
|
*/
|
|
function showFormAdvancedConfig() {
|
|
|
|
$ID = $this->getField('id');
|
|
$hidden = '';
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
|
|
echo "<tr class='tab_bg_2'><th colspan='4'>";
|
|
echo "<input type='hidden' name='id' value='$ID'>". __('Advanced information')."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td>" . __('Use TLS') . "</td><td>";
|
|
if (function_exists("ldap_start_tls")) {
|
|
Dropdown::showYesNo('use_tls', $this->fields["use_tls"]);
|
|
} else {
|
|
echo "<input type='hidden' name='use_tls' value='0'>".__('ldap_start_tls does not exist');
|
|
}
|
|
echo "</td>";
|
|
echo "<td>" . __('LDAP directory time zone') . "</td><td>";
|
|
Dropdown::showGMT("time_offset", $this->fields["time_offset"]);
|
|
echo"</td></tr>";
|
|
|
|
if (self::isLdapPageSizeAvailable(false, false)) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td>" . __('Use paged results') . "</td><td>";
|
|
Dropdown::showYesNo('can_support_pagesize', $this->fields["can_support_pagesize"]);
|
|
echo "</td>";
|
|
echo "<td>" . __('Page size') . "</td><td>";
|
|
Dropdown::showNumber("pagesize", ['value' => $this->fields['pagesize'],
|
|
'min' => 100,
|
|
'max' => 100000,
|
|
'step' => 100]);
|
|
echo"</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td>" . __('Maximum number of results') . "</td><td>";
|
|
Dropdown::showNumber('ldap_maxlimit', ['value' => $this->fields['ldap_maxlimit'],
|
|
'min' => 100,
|
|
'max' => 999999,
|
|
'step' => 100,
|
|
'toadd' => [0 => __('Unlimited')]]);
|
|
echo "</td><td colspan='2'></td></tr>";
|
|
|
|
} else {
|
|
$hidden .= "<input type='hidden' name='can_support_pagesize' value='0'>";
|
|
$hidden .= "<input type='hidden' name='pagesize' value='0'>";
|
|
$hidden .= "<input type='hidden' name='ldap_maxlimit' value='0'>";
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td>" . __('How LDAP aliases should be handled') . "</td><td colspan='4'>";
|
|
$alias_options = [
|
|
LDAP_DEREF_NEVER => __('Never dereferenced (default)'),
|
|
LDAP_DEREF_ALWAYS => __('Always dereferenced'),
|
|
LDAP_DEREF_SEARCHING => __('Dereferenced during the search (but not when locating)'),
|
|
LDAP_DEREF_FINDING => __('Dereferenced when locating (not during the search)'),
|
|
];
|
|
Dropdown::showFromArray("deref_option", $alias_options,
|
|
['value' => $this->fields["deref_option"]]);
|
|
echo"</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td>".__('Domain name used by inventory tool for link the user')."</td>";
|
|
echo "<td colspan='3'>";
|
|
Html::autocompletionTextField($this, "inventory_domain", ['size' => 100]);
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
|
|
echo $hidden;
|
|
echo "</td></tr>";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
|
|
}
|
|
|
|
/**
|
|
* Show config replicates form
|
|
*
|
|
* @var DBmysql $DB
|
|
*
|
|
* @return void
|
|
*/
|
|
function showFormReplicatesConfig() {
|
|
global $DB;
|
|
|
|
$ID = $this->getField('id');
|
|
$target = $this->getFormURL();
|
|
$rand = mt_rand();
|
|
|
|
AuthLdapReplicate::addNewReplicateForm($target, $ID);
|
|
|
|
$iterator = $DB->request([
|
|
'FROM' => 'glpi_authldapreplicates',
|
|
'WHERE' => [
|
|
'authldaps_id' => $ID
|
|
],
|
|
'ORDER' => ['name']
|
|
]);
|
|
|
|
if (($nb = count($iterator)) > 0) {
|
|
echo "<br>";
|
|
|
|
echo "<div class='center'>";
|
|
Html::openMassiveActionsForm('massAuthLdapReplicate'.$rand);
|
|
$massiveactionparams = ['num_displayed' => min($_SESSION['glpilist_limit'], $nb),
|
|
'container' => 'massAuthLdapReplicate'.$rand];
|
|
Html::showMassiveActions($massiveactionparams);
|
|
echo "<input type='hidden' name='id' value='$ID'>";
|
|
echo "<table class='tab_cadre_fixehov'>";
|
|
echo "<tr class='noHover'>".
|
|
"<th colspan='4'>".__('List of LDAP directory replicates') . "</th></tr>";
|
|
|
|
if (isset($_SESSION["LDAP_TEST_MESSAGE"])) {
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo $_SESSION["LDAP_TEST_MESSAGE"];
|
|
echo"</td></tr>";
|
|
unset($_SESSION["LDAP_TEST_MESSAGE"]);
|
|
}
|
|
$header_begin = "<tr>";
|
|
$header_top = "<th>".Html::getCheckAllAsCheckbox('massAuthLdapReplicate'.$rand)."</th>";
|
|
$header_bottom = "<th>".Html::getCheckAllAsCheckbox('massAuthLdapReplicate'.$rand)."</th>";
|
|
$header_end = "<th class='center b'>".__('Name')."</th>";
|
|
$header_end .= "<th class='center b'>"._n('Replicate', 'Replicates', 1)."</th>".
|
|
"<th class='center'></th></tr>";
|
|
echo $header_begin.$header_top.$header_end;
|
|
|
|
while ($ldap_replicate = $iterator->next()) {
|
|
echo "<tr class='tab_bg_1'><td class='center' width='10'>";
|
|
Html::showMassiveActionCheckBox('AuthLdapReplicate', $ldap_replicate["id"]);
|
|
echo "</td>";
|
|
echo "<td class='center'>" . $ldap_replicate["name"] . "</td>";
|
|
echo "<td class='center'>".sprintf(__('%1$s: %2$s'), $ldap_replicate["host"],
|
|
$ldap_replicate["port"]);
|
|
echo "</td>";
|
|
echo "<td class='center'>";
|
|
Html::showSimpleForm(static::getFormURL(),
|
|
'test_ldap_replicate', _sx('button', 'Test'),
|
|
['id' => $ID,
|
|
'ldap_replicate_id' => $ldap_replicate["id"]]);
|
|
echo "</td></tr>";
|
|
}
|
|
echo $header_begin.$header_bottom.$header_end;
|
|
echo "</table>";
|
|
$massiveactionparams['ontop'] = false;
|
|
Html::showMassiveActions($massiveactionparams);
|
|
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build a dropdown
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @param array $options Options
|
|
*
|
|
* @return string
|
|
*/
|
|
static function dropdownGroupSearchType(array $options) {
|
|
|
|
$p = [
|
|
'name' => 'group_search_type',
|
|
'value' => self::GROUP_SEARCH_USER,
|
|
'display' => true,
|
|
];
|
|
|
|
if (count($options)) {
|
|
foreach ($options as $key => $val) {
|
|
$p[$key] = $val;
|
|
}
|
|
}
|
|
|
|
$tab = self::getGroupSearchTypeName();
|
|
return Dropdown::showFromArray($p['name'], $tab, $p);
|
|
}
|
|
|
|
/**
|
|
* Get the possible value for contract alert
|
|
*
|
|
* @since 0.83
|
|
*
|
|
* @param integer $val if not set, ask for all values, else for 1 value (default NULL)
|
|
*
|
|
* @return array|string
|
|
*/
|
|
static function getGroupSearchTypeName($val = null) {
|
|
$tmp = [
|
|
self::GROUP_SEARCH_USER => __('In users'),
|
|
self::GROUP_SEARCH_GROUP => __('In groups'),
|
|
self::GROUP_SEARCH_BOTH => __('In users and groups')
|
|
];
|
|
|
|
if (is_null($val)) {
|
|
return $tmp;
|
|
}
|
|
if (isset($tmp[$val])) {
|
|
return $tmp[$val];
|
|
}
|
|
return NOT_AVAILABLE;
|
|
}
|
|
|
|
/**
|
|
* Show group config form
|
|
*
|
|
* @return void
|
|
*/
|
|
function showFormGroupsConfig() {
|
|
|
|
$ID = $this->getField('id');
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
|
|
echo "<input type='hidden' name='id' value='$ID'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
|
|
echo "<tr><th class='center' colspan='4'>" . __('Belonging to groups') . "</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Search type') . "</td><td>";
|
|
self::dropdownGroupSearchType(['value' => $this->fields["group_search_type"]]);
|
|
echo "</td>";
|
|
echo "<td>" . __('User attribute containing its groups') . "</td>";
|
|
echo "<td><input type='text' name='group_field' value='".$this->fields["group_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Filter to search in groups')."</td><td colspan='3'>";
|
|
echo "<textarea cols='100' rows='1' name='group_condition'>".$this->fields["group_condition"];
|
|
echo "</textarea>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Group attribute containing its users') . "</td>";
|
|
echo "<td><input type='text' name='group_member_field' value='".
|
|
$this->fields["group_member_field"]."'></td>";
|
|
echo "<td>" . __('Use DN in the search') . "</td>";
|
|
echo "<td>";
|
|
Dropdown::showYesNo("use_dn", $this->fields["use_dn"]);
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
|
|
echo "</td></tr>";
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
/**
|
|
* Show ldap test form
|
|
*
|
|
* @return void
|
|
*/
|
|
function showFormTestLDAP () {
|
|
|
|
$ID = $this->getField('id');
|
|
|
|
if ($ID > 0) {
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
|
|
echo "<input type='hidden' name='id' value='$ID'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='4'>" . __('Test of connection to LDAP directory') . "</th></tr>";
|
|
|
|
if (isset($_SESSION["LDAP_TEST_MESSAGE"])) {
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo $_SESSION["LDAP_TEST_MESSAGE"];
|
|
echo"</td></tr>";
|
|
unset($_SESSION["LDAP_TEST_MESSAGE"]);
|
|
}
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo "<input type='submit' name='test_ldap' class='submit' value=\"".
|
|
_sx('button', 'Test')."\">";
|
|
echo "</td></tr>";
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show user config form
|
|
*
|
|
* @return void
|
|
*/
|
|
function showFormUserConfig() {
|
|
|
|
$ID = $this->getField('id');
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
|
|
echo "<input type='hidden' name='id' value='$ID'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<th class='center' colspan='4'>" . __('Binding to the LDAP directory') . "</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . __('Surname') . "</td>";
|
|
echo "<td><input type='text' name='realname_field' value='".
|
|
$this->fields["realname_field"]."'></td>";
|
|
echo "<td>" . __('First name') . "</td>";
|
|
echo "<td><input type='text' name='firstname_field' value='".
|
|
$this->fields["firstname_field"]."'></td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . __('Comments') . "</td>";
|
|
echo "<td><input type='text' name='comment_field' value='".$this->fields["comment_field"]."'>";
|
|
echo "</td>";
|
|
echo "<td>" . __('Administrative number') . "</td>";
|
|
echo "<td>";
|
|
echo "<input type='text' name='registration_number_field' value='".
|
|
$this->fields["registration_number_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'>";
|
|
echo "<td>" . _n('Email', 'Emails', 1) . "</td>";
|
|
echo "<td><input type='text' name='email1_field' value='".$this->fields["email1_field"]."'>";
|
|
echo "</td>";
|
|
echo "<td>" . sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '2') . "</td>";
|
|
echo "<td><input type='text' name='email2_field' value='".$this->fields["email2_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'>";
|
|
echo "<td>" . sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '3') . "</td>";
|
|
echo "<td><input type='text' name='email3_field' value='".$this->fields["email3_field"]."'>";
|
|
echo "</td>";
|
|
echo "<td>" . sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '4') . "</td>";
|
|
echo "<td><input type='text' name='email4_field' value='".$this->fields["email4_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . _x('ldap', 'Phone') . "</td>";
|
|
echo "<td><input type='text' name='phone_field'value='".$this->fields["phone_field"]."'>";
|
|
echo "</td>";
|
|
echo "<td>" . __('Phone 2') . "</td>";
|
|
echo "<td><input type='text' name='phone2_field'value='".$this->fields["phone2_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . __('Mobile phone') . "</td>";
|
|
echo "<td><input type='text' name='mobile_field'value='".$this->fields["mobile_field"]."'>";
|
|
echo "</td>";
|
|
echo "<td>" . _x('person', 'Title') . "</td>";
|
|
echo "<td><input type='text' name='title_field' value='".$this->fields["title_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . __('Category') . "</td>";
|
|
echo "<td><input type='text' name='category_field' value='".
|
|
$this->fields["category_field"]."'></td>";
|
|
echo "<td>" . __('Language') . "</td>";
|
|
echo "<td><input type='text' name='language_field' value='".
|
|
$this->fields["language_field"]."'></td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . __('Picture') . "</td>";
|
|
echo "<td><input type='text' name='picture_field' value='".
|
|
$this->fields["picture_field"]."'></td>";
|
|
echo "<td>" . Location::getTypeName(1) . "</td>";
|
|
echo "<td><input type='text' name='location_field' value='".$this->fields["location_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>" . __('Responsible') . "</td>";
|
|
echo "<td><input type='text' name='responsible_field' value='".
|
|
$this->fields["responsible_field"]."'></td>";
|
|
echo "<td colspan='2'></td></tr>";
|
|
|
|
echo "<tr><td colspan=4 class='center green'>".__('You can use a field name or an expression using various %{fieldname}').
|
|
" <br />".__('Example for location: %{city} > %{roomnumber}')."</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
|
|
echo "</td></tr>";
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
/**
|
|
* Show entity config form
|
|
*
|
|
* @return void
|
|
*/
|
|
function showFormEntityConfig() {
|
|
|
|
$ID = $this->getField('id');
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
|
|
echo "<input type='hidden' name='id' value='$ID'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
|
|
echo "<tr><th class='center' colspan='4'>". __('Import entities from LDAP directory').
|
|
"</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Attribute representing entity') . "</td>";
|
|
echo "<td colspan='3'>";
|
|
echo "<input type='text' name='entity_field' value='".$this->fields["entity_field"]."'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Search filter for entities') . "</td>";
|
|
echo "<td colspan='3'>";
|
|
echo "<input type='text' name='entity_condition' value='".$this->fields["entity_condition"]."'
|
|
size='100'></td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='4'>";
|
|
echo "<input type='submit' name='update' class='submit' value=\"".__s('Save')."\">";
|
|
echo "</td></tr>";
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
function defineTabs($options = []) {
|
|
|
|
$ong = [];
|
|
$this->addDefaultFormTab($ong);
|
|
$this->addStandardTab(__CLASS__, $ong, $options);
|
|
$this->addImpactTab($ong, $options);
|
|
$this->addStandardTab('Log', $ong, $options);
|
|
|
|
return $ong;
|
|
}
|
|
|
|
function rawSearchOptions() {
|
|
$tab = [];
|
|
|
|
$tab[] = [
|
|
'id' => 'common',
|
|
'name' => $this->getTypeName(1)
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '1',
|
|
'table' => $this->getTable(),
|
|
'field' => 'name',
|
|
'name' => __('Name'),
|
|
'datatype' => 'itemlink',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '2',
|
|
'table' => $this->getTable(),
|
|
'field' => 'id',
|
|
'name' => __('ID'),
|
|
'datatype' => 'number',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '3',
|
|
'table' => $this->getTable(),
|
|
'field' => 'host',
|
|
'name' => __('Server'),
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '4',
|
|
'table' => $this->getTable(),
|
|
'field' => 'port',
|
|
'name' => _n('Port', 'Ports', 1),
|
|
'datatype' => 'integer'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '5',
|
|
'table' => $this->getTable(),
|
|
'field' => 'basedn',
|
|
'name' => __('BaseDN'),
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '6',
|
|
'table' => $this->getTable(),
|
|
'field' => 'condition',
|
|
'name' => __('Connection filter'),
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '7',
|
|
'table' => $this->getTable(),
|
|
'field' => 'is_default',
|
|
'name' => __('Default server'),
|
|
'datatype' => 'bool',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '8',
|
|
'table' => $this->getTable(),
|
|
'field' => 'login_field',
|
|
'name' => __('Login field'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '9',
|
|
'table' => $this->getTable(),
|
|
'field' => 'realname_field',
|
|
'name' => __('Surname'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '10',
|
|
'table' => $this->getTable(),
|
|
'field' => 'firstname_field',
|
|
'name' => __('First name'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '11',
|
|
'table' => $this->getTable(),
|
|
'field' => 'phone_field',
|
|
'name' => _x('ldap', 'Phone'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '12',
|
|
'table' => $this->getTable(),
|
|
'field' => 'phone2_field',
|
|
'name' => __('Phone 2'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '13',
|
|
'table' => $this->getTable(),
|
|
'field' => 'mobile_field',
|
|
'name' => __('Mobile phone'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '14',
|
|
'table' => $this->getTable(),
|
|
'field' => 'title_field',
|
|
'name' => _x('person', 'Title'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '15',
|
|
'table' => $this->getTable(),
|
|
'field' => 'category_field',
|
|
'name' => __('Category'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '16',
|
|
'table' => $this->getTable(),
|
|
'field' => 'comment',
|
|
'name' => __('Comments'),
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '17',
|
|
'table' => $this->getTable(),
|
|
'field' => 'email1_field',
|
|
'name' => _n('Email', 'Emails', 1),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '25',
|
|
'table' => $this->getTable(),
|
|
'field' => 'email2_field',
|
|
'name' => sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '2'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '26',
|
|
'table' => $this->getTable(),
|
|
'field' => 'email3_field',
|
|
'name' => sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '3'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '27',
|
|
'table' => $this->getTable(),
|
|
'field' => 'email4_field',
|
|
'name' => sprintf(__('%1$s %2$s'), _n('Email', 'Emails', 1), '4'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '18',
|
|
'table' => $this->getTable(),
|
|
'field' => 'use_dn',
|
|
'name' => __('Use DN in the search'),
|
|
'datatype' => 'bool',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '19',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_mod',
|
|
'name' => __('Last update'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '121',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_creation',
|
|
'name' => __('Creation date'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '20',
|
|
'table' => $this->getTable(),
|
|
'field' => 'language_field',
|
|
'name' => __('Language'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '21',
|
|
'table' => $this->getTable(),
|
|
'field' => 'group_field',
|
|
'name' => __('User attribute containing its groups'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '22',
|
|
'table' => $this->getTable(),
|
|
'field' => 'group_condition',
|
|
'name' => __('Filter to search in groups'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '23',
|
|
'table' => $this->getTable(),
|
|
'field' => 'group_member_field',
|
|
'name' => __('Group attribute containing its users'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '24',
|
|
'table' => $this->getTable(),
|
|
'field' => 'group_search_type',
|
|
'datatype' => 'specific',
|
|
'name' => __('Search type'),
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '30',
|
|
'table' => $this->getTable(),
|
|
'field' => 'is_active',
|
|
'name' => __('Active'),
|
|
'datatype' => 'bool'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '28',
|
|
'table' => $this->getTable(),
|
|
'field' => 'sync_field',
|
|
'name' => __('Synchronization field'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '29',
|
|
'table' => $this->getTable(),
|
|
'field' => 'responsible_field',
|
|
'name' => __('Responsible'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '31',
|
|
'table' => $this->getTable(),
|
|
'field' => 'inventory_domain',
|
|
'name' => __('Domain name used by inventory tool'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
return $tab;
|
|
}
|
|
|
|
/**
|
|
* Show system informations form
|
|
*
|
|
* @param integer $width The number of characters at which the string will be wrapped.
|
|
*
|
|
* @return void
|
|
*/
|
|
function showSystemInformations($width) {
|
|
|
|
// No need to translate, this part always display in english (for copy/paste to forum)
|
|
|
|
$ldap_servers = self::getLdapServers();
|
|
|
|
if (!empty($ldap_servers)) {
|
|
echo "<tr class='tab_bg_2'><th>" . self::getTypeName(Session::getPluralNumber()) . "</th></tr>\n";
|
|
echo "<tr class='tab_bg_1'><td><pre>\n \n";
|
|
foreach ($ldap_servers as $value) {
|
|
$fields = ['Server' => 'host',
|
|
'Port' => 'port',
|
|
'BaseDN' => 'basedn',
|
|
'Connection filter' => 'condition',
|
|
'RootDN' => 'rootdn',
|
|
'Use TLS' => 'use_tls'];
|
|
$msg = '';
|
|
$first = true;
|
|
foreach ($fields as $label => $field) {
|
|
$msg .= (!$first ? ', ' : '').
|
|
$label.': '.
|
|
($value[$field]? '\''.$value[$field].'\'' : 'none');
|
|
$first = false;
|
|
}
|
|
echo wordwrap($msg."\n", $width, "\n\t\t");
|
|
}
|
|
echo "\n</pre></td></tr>";
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get LDAP fields to sync to GLPI data from a glpi_authldaps array
|
|
*
|
|
* @param array $authtype_array Authentication method config array (from table)
|
|
*
|
|
* @return array of "user table field name" => "config value"
|
|
*/
|
|
static function getSyncFields(array $authtype_array) {
|
|
|
|
$ret = [];
|
|
$fields = ['login_field' => 'name',
|
|
'email1_field' => 'email1',
|
|
'email2_field' => 'email2',
|
|
'email3_field' => 'email3',
|
|
'email4_field' => 'email4',
|
|
'realname_field' => 'realname',
|
|
'firstname_field' => 'firstname',
|
|
'phone_field' => 'phone',
|
|
'phone2_field' => 'phone2',
|
|
'mobile_field' => 'mobile',
|
|
'location_field' => 'locations_id',
|
|
'comment_field' => 'comment',
|
|
'title_field' => 'usertitles_id',
|
|
'category_field' => 'usercategories_id',
|
|
'language_field' => 'language',
|
|
'registration_number_field' => 'registration_number',
|
|
'picture_field' => 'picture',
|
|
'responsible_field' => 'users_id_supervisor',
|
|
'sync_field' => 'sync_field'];
|
|
|
|
foreach ($fields as $key => $val) {
|
|
if (isset($authtype_array[$key]) && !empty($authtype_array[$key])) {
|
|
$ret[$val] = $authtype_array[$key];
|
|
}
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* Display LDAP filter
|
|
*
|
|
* @param string $target target for the form
|
|
* @param boolean $users for user? (true by default)
|
|
*
|
|
* @return void
|
|
*/
|
|
static function displayLdapFilter($target, $users = true) {
|
|
|
|
$config_ldap = new self();
|
|
if (!isset($_SESSION['ldap_server'])) {
|
|
throw new \RuntimeException('LDAP server must be set!');
|
|
}
|
|
$config_ldap->getFromDB($_SESSION['ldap_server']);
|
|
|
|
if ($users) {
|
|
$filter_name1 = "condition";
|
|
$filter_var = "ldap_filter";
|
|
|
|
} else {
|
|
$filter_var = "ldap_group_filter";
|
|
switch ($config_ldap->fields["group_search_type"]) {
|
|
case self::GROUP_SEARCH_USER:
|
|
$filter_name1 = "condition";
|
|
break;
|
|
|
|
case self::GROUP_SEARCH_GROUP:
|
|
$filter_name1 = "group_condition";
|
|
break;
|
|
|
|
case self::GROUP_SEARCH_BOTH:
|
|
$filter_name1 = "group_condition";
|
|
$filter_name2 = "condition";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isset($_SESSION[$filter_var]) || ($_SESSION[$filter_var] == '')) {
|
|
$_SESSION[$filter_var] = $config_ldap->fields[$filter_name1];
|
|
}
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' action='$target'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='2'>" . ($users?__('Search filter for users')
|
|
:__('Filter to search in groups')) . "</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center'>";
|
|
echo "<input type='text' name='ldap_filter' value='". $_SESSION[$filter_var] ."' size='70'>";
|
|
//Only display when looking for groups in users AND groups
|
|
if (!$users
|
|
&& ($config_ldap->fields["group_search_type"] == self::GROUP_SEARCH_BOTH)) {
|
|
|
|
if (!isset($_SESSION["ldap_group_filter2"]) || ($_SESSION["ldap_group_filter2"] == '')) {
|
|
$_SESSION["ldap_group_filter2"] = $config_ldap->fields[$filter_name2];
|
|
}
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr><th colspan='2'>" . __('Search filter for users') . "</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center'>";
|
|
echo "<input type='text' name='ldap_filter2' value='".$_SESSION["ldap_group_filter2"]."'
|
|
size='70'></td></tr>";
|
|
}
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center'>";
|
|
echo "<input class=submit type='submit' name='change_ldap_filter' value=\"".
|
|
_sx('button', 'Post')."\"></td></tr>";
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Converts LDAP timestamps over to Unix timestamps
|
|
*
|
|
* @param string $ldapstamp LDAP timestamp
|
|
* @param integer $ldap_time_offset time offset (default 0)
|
|
*
|
|
* @return integer unix timestamp
|
|
*/
|
|
static function ldapStamp2UnixStamp($ldapstamp, $ldap_time_offset = 0) {
|
|
global $CFG_GLPI;
|
|
|
|
//Check if timestamp is well format, otherwise return ''
|
|
if (!preg_match("/[\d]{14}(\.[\d]{0,4})*Z/", $ldapstamp)) {
|
|
return '';
|
|
}
|
|
|
|
$year = substr($ldapstamp, 0, 4);
|
|
$month = substr($ldapstamp, 4, 2);
|
|
$day = substr($ldapstamp, 6, 2);
|
|
$hour = substr($ldapstamp, 8, 2);
|
|
$minute = substr($ldapstamp, 10, 2);
|
|
$seconds = substr($ldapstamp, 12, 2);
|
|
$stamp = gmmktime($hour, $minute, $seconds, $month, $day, $year);
|
|
$stamp += $CFG_GLPI["time_offset"]-$ldap_time_offset;
|
|
|
|
return $stamp;
|
|
}
|
|
|
|
|
|
/**
|
|
* Converts a Unix timestamp to an LDAP timestamps
|
|
*
|
|
* @param string $date datetime
|
|
*
|
|
* @return string ldap timestamp
|
|
*/
|
|
static function date2ldapTimeStamp($date) {
|
|
return date("YmdHis", strtotime($date)).'.0Z';
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the LDAP field to use for user synchronization
|
|
* It may be sync_field if defined, or login_field
|
|
* @since 9.2
|
|
*
|
|
* @return string the ldap field to use for user synchronization
|
|
*/
|
|
public function getLdapIdentifierToUse() {
|
|
if (!empty($this->fields['sync_field'])) {
|
|
return $this->fields['sync_field'];
|
|
} else {
|
|
return $this->fields['login_field'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the database field to use for user synchronization
|
|
* @since 9.2
|
|
*
|
|
* @return string the database field to use for user synchronization
|
|
*/
|
|
public function getDatabaseIdentifierToUse() {
|
|
if (!empty($this->fields['sync_field'])) {
|
|
return 'sync_field';
|
|
} else {
|
|
return 'name';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates if there's a sync_field enabled in the LDAP configuration
|
|
* @since 9.2
|
|
*
|
|
* @return boolean true if the sync_field is enabled (the field is filled)
|
|
*/
|
|
public function isSyncFieldEnabled() {
|
|
return (!empty($this->fields['sync_field']));
|
|
}
|
|
|
|
/**
|
|
* Check if the sync_field is configured for an LDAP server
|
|
*
|
|
* @since 9.2
|
|
* @param integer authldaps_id the LDAP server ID
|
|
* @return boolean true if configured, false if not configured
|
|
*/
|
|
public static function isSyncFieldConfigured($authldaps_id) {
|
|
$authldap = new self();
|
|
$authldap->getFromDB($authldaps_id);
|
|
return ($authldap->isSyncFieldEnabled());
|
|
}
|
|
|
|
/**
|
|
* Test a LDAP connection
|
|
*
|
|
* @param integer $auths_id ID of the LDAP server
|
|
* @param integer $replicate_id use a replicate if > 0 (default -1)
|
|
*
|
|
* @return boolean connection succeeded?
|
|
*/
|
|
static function testLDAPConnection($auths_id, $replicate_id = -1) {
|
|
|
|
$config_ldap = new self();
|
|
$res = $config_ldap->getFromDB($auths_id);
|
|
|
|
// we prevent some delay...
|
|
if (!$res) {
|
|
return false;
|
|
}
|
|
|
|
//Test connection to a replicate
|
|
if ($replicate_id != -1) {
|
|
$replicate = new AuthLdapReplicate();
|
|
$replicate->getFromDB($replicate_id);
|
|
$host = $replicate->fields["host"];
|
|
$port = $replicate->fields["port"];
|
|
|
|
} else {
|
|
//Test connection to a master ldap server
|
|
$host = $config_ldap->fields['host'];
|
|
$port = $config_ldap->fields['port'];
|
|
}
|
|
$ds = self::connectToServer($host, $port, $config_ldap->fields['rootdn'],
|
|
Toolbox::sodiumDecrypt($config_ldap->fields['rootdn_passwd']),
|
|
$config_ldap->fields['use_tls'],
|
|
$config_ldap->fields['deref_option']);
|
|
if ($ds) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Display a warnign about size limit
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @param boolean $limitexceeded (false by default)
|
|
*
|
|
* @return void
|
|
*/
|
|
static function displaySizeLimitWarning($limitexceeded = false) {
|
|
global $CFG_GLPI;
|
|
|
|
if ($limitexceeded) {
|
|
echo "<div class='firstbloc'><table class='tab_cadre_fixe'>";
|
|
echo "<tr><th class='red'>";
|
|
echo "<img class='center' src='".$CFG_GLPI["root_doc"]."/pics/warning.png'
|
|
alt='".__('Warning')."'> ".
|
|
__('Warning: The request exceeds the limit of the directory. The results are only partial.');
|
|
echo "</th></tr></table><div>";
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Show LDAP users to add or synchronise
|
|
*
|
|
* @return void
|
|
*/
|
|
static function showLdapUsers() {
|
|
|
|
$values = [
|
|
'order' => 'DESC',
|
|
'start' => 0,
|
|
];
|
|
|
|
foreach ($_SESSION['ldap_import'] as $option => $value) {
|
|
$values[$option] = $value;
|
|
}
|
|
|
|
$rand = mt_rand();
|
|
$results = [];
|
|
$limitexceeded = false;
|
|
$ldap_users = self::getUsers($values, $results, $limitexceeded);
|
|
|
|
$config_ldap = new AuthLDAP();
|
|
$config_ldap->getFromDB($values['authldaps_id']);
|
|
|
|
if (is_array($ldap_users)) {
|
|
$numrows = count($ldap_users);
|
|
|
|
if ($numrows > 0) {
|
|
self::displaySizeLimitWarning($limitexceeded);
|
|
|
|
Html::printPager($values['start'], $numrows, $_SERVER['PHP_SELF'], '');
|
|
|
|
// delete end
|
|
array_splice($ldap_users, $values['start'] + $_SESSION['glpilist_limit']);
|
|
// delete begin
|
|
if ($values['start'] > 0) {
|
|
array_splice($ldap_users, 0, $values['start']);
|
|
}
|
|
|
|
$form_action = '';
|
|
$textbutton = '';
|
|
if ($_SESSION['ldap_import']['mode']) {
|
|
$textbutton = _x('button', 'Synchronize');
|
|
$form_action = __CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'sync';
|
|
} else {
|
|
$textbutton = _x('button', 'Import');
|
|
$form_action = __CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'import';
|
|
}
|
|
|
|
Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
|
|
$massiveactionparams = ['num_displayed' => min(count($ldap_users),
|
|
$_SESSION['glpilist_limit']),
|
|
'container' => 'mass'.__CLASS__.$rand,
|
|
'specific_actions' => [$form_action => $textbutton]];
|
|
Html::showMassiveActions($massiveactionparams);
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr>";
|
|
echo "<th width='10'>";
|
|
echo Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
|
|
echo "</th>";
|
|
$num = 0;
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
echo Search::showHeaderItem(Search::HTML_OUTPUT, __('Synchronization field'), $num,
|
|
$_SERVER['PHP_SELF'].
|
|
"?order=".($values['order']=="DESC"?"ASC":"DESC"));
|
|
}
|
|
echo Search::showHeaderItem(Search::HTML_OUTPUT, User::getTypeName(Session::getPluralNumber()), $num,
|
|
$_SERVER['PHP_SELF'].
|
|
"?order=".($values['order']=="DESC"?"ASC":"DESC"));
|
|
echo "<th>".__('Last update in the LDAP directory')."</th>";
|
|
if ($_SESSION['ldap_import']['mode']) {
|
|
echo "<th>".__('Last update in GLPI')."</th>";
|
|
}
|
|
echo "</tr>";
|
|
|
|
foreach ($ldap_users as $userinfos) {
|
|
echo "<tr class='tab_bg_2 center'>";
|
|
//Need to use " instead of ' because it doesn't work with names with ' inside !
|
|
echo "<td>";
|
|
echo Html::getMassiveActionCheckBox(__CLASS__, $userinfos['uid']);
|
|
echo "</td>";
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
echo "<td>" . $userinfos['uid'] . "</td>";
|
|
}
|
|
echo "<td>";
|
|
if (isset($userinfos['id']) && User::canView()) {
|
|
echo "<a href='".$userinfos['link']."'>". $userinfos['name'] . "</a>";
|
|
} else {
|
|
echo $userinfos['link'];
|
|
}
|
|
echo "</td>";
|
|
|
|
if ($userinfos['stamp'] != '') {
|
|
echo "<td>" .Html::convDateTime(date("Y-m-d H:i:s", $userinfos['stamp'])). "</td>";
|
|
} else {
|
|
echo "<td> </td>";
|
|
}
|
|
if ($_SESSION['ldap_import']['mode']) {
|
|
if ($userinfos['date_sync'] != '') {
|
|
echo "<td>" . Html::convDateTime($userinfos['date_sync']) . "</td>";
|
|
}
|
|
}
|
|
echo "</tr>";
|
|
}
|
|
echo "<tr>";
|
|
echo "<th width='10'>";
|
|
echo Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
|
|
echo "</th>";
|
|
$num = 0;
|
|
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
echo Search::showHeaderItem(Search::HTML_OUTPUT, __('Synchronization field'), $num,
|
|
$_SERVER['PHP_SELF'].
|
|
"?order=".($values['order']=="DESC"?"ASC":"DESC"));
|
|
}
|
|
echo Search::showHeaderItem(Search::HTML_OUTPUT, User::getTypeName(Session::getPluralNumber()), $num,
|
|
$_SERVER['PHP_SELF'].
|
|
"?order=".($values['order']=="DESC"?"ASC":"DESC"));
|
|
echo "<th>".__('Last update in the LDAP directory')."</th>";
|
|
if ($_SESSION['ldap_import']['mode']) {
|
|
echo "<th>".__('Last update in GLPI')."</th>";
|
|
}
|
|
echo "</tr>";
|
|
echo "</table>";
|
|
|
|
$massiveactionparams['ontop'] = false;
|
|
Html::showMassiveActions($massiveactionparams);
|
|
Html::closeForm();
|
|
|
|
Html::printPager($values['start'], $numrows, $_SERVER['PHP_SELF'], '');
|
|
} else {
|
|
echo "<div class='center b'>".
|
|
($_SESSION['ldap_import']['mode']?__('No user to be synchronized')
|
|
:__('No user to be imported'))."</div>";
|
|
}
|
|
} else {
|
|
echo "<div class='center b'>".
|
|
($_SESSION['ldap_import']['mode']?__('No user to be synchronized')
|
|
:__('No user to be imported'))."</div>";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Search users
|
|
*
|
|
* @param resource $ds An LDAP link identifier
|
|
* @param array $values values to search
|
|
* @param string $filter search filter
|
|
* @param array $attrs An array of the required attributes
|
|
* @param boolean $limitexceeded is limit exceeded
|
|
* @param array $user_infos user informations
|
|
* @param array $ldap_users ldap users
|
|
* @param object $config_ldap ldap configuration
|
|
*
|
|
* @return boolean
|
|
*/
|
|
static function searchForUsers($ds, $values, $filter, $attrs, &$limitexceeded, &$user_infos,
|
|
&$ldap_users, $config_ldap) {
|
|
|
|
//If paged results cannot be used (PHP < 5.4)
|
|
$cookie = ''; //Cookie used to perform query using pages
|
|
$count = 0; //Store the number of results ldap_search
|
|
|
|
do {
|
|
$filter = Toolbox::unclean_cross_side_scripting_deep(Toolbox::stripslashes_deep($filter));
|
|
if (self::isLdapPageSizeAvailable($config_ldap)) {
|
|
if (version_compare(PHP_VERSION, '7.3') < 0) {
|
|
//prior to PHP 7.3, use ldap_control_paged_result
|
|
// phpcs:ignore Generic.PHP.DeprecatedFunctions
|
|
ldap_control_paged_result($ds, $config_ldap->fields['pagesize'], true, $cookie);
|
|
$sr = @ldap_search($ds, $values['basedn'], $filter, $attrs);
|
|
} else {
|
|
//since PHP 7.3, send serverctrls to ldap_search
|
|
$controls = [
|
|
[
|
|
'oid' =>LDAP_CONTROL_PAGEDRESULTS,
|
|
'iscritical' => true,
|
|
'value' => [
|
|
'size' => $config_ldap->fields['pagesize'],
|
|
'cookie' => $cookie
|
|
]
|
|
]
|
|
];
|
|
$sr = @ldap_search($ds, $values['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
|
|
ldap_parse_result($ds, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls);
|
|
if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) {
|
|
$cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'];
|
|
} else {
|
|
$cookie = '';
|
|
}
|
|
}
|
|
} else {
|
|
$sr = @ldap_search($ds, $values['basedn'], $filter, $attrs);
|
|
}
|
|
|
|
if ($sr) {
|
|
if (in_array(ldap_errno($ds), [4,11])) {
|
|
// openldap return 4 for Size limit exceeded
|
|
$limitexceeded = true;
|
|
}
|
|
|
|
$info = self::get_entries_clean($ds, $sr);
|
|
if (in_array(ldap_errno($ds), [4,11])) {
|
|
// openldap return 4 for Size limit exceeded
|
|
$limitexceeded = true;
|
|
}
|
|
|
|
$count += $info['count'];
|
|
//If page results are enabled and the number of results is greater than the maximum allowed
|
|
//warn user that limit is exceeded and stop search
|
|
if (self::isLdapPageSizeAvailable($config_ldap)
|
|
&& $config_ldap->fields['ldap_maxlimit']
|
|
&& ($count > $config_ldap->fields['ldap_maxlimit'])) {
|
|
$limitexceeded = true;
|
|
break;
|
|
}
|
|
|
|
$field_for_sync = $config_ldap->getLdapIdentifierToUse();
|
|
$login_field = $config_ldap->fields['login_field'];
|
|
|
|
for ($ligne = 0; $ligne < $info["count"]; $ligne++) {
|
|
if (in_array($field_for_sync, $info[$ligne])) {
|
|
$uid = self::getFieldValue($info[$ligne], $field_for_sync);
|
|
|
|
if ($login_field != $field_for_sync && !isset($info[$ligne][$login_field])) {
|
|
Toolbox::logWarning("Missing field $login_field for LDAP entry $field_for_sync $uid");
|
|
//Login field may be missing... Skip the user
|
|
continue;
|
|
}
|
|
|
|
$user_infos[$uid]["timestamp"] = self::ldapStamp2UnixStamp(
|
|
$info[$ligne]['modifytimestamp'][0],
|
|
$config_ldap->fields['time_offset']
|
|
);
|
|
$user_infos[$uid]["user_dn"] = $info[$ligne]['dn'];
|
|
$user_infos[$uid][$field_for_sync] = $uid;
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
$user_infos[$uid][$login_field] = $info[$ligne][$login_field][0];
|
|
}
|
|
|
|
if ($values['mode'] == self::ACTION_IMPORT) {
|
|
//If ldap add
|
|
$ldap_users[$uid] = $uid;
|
|
} else {
|
|
//If ldap synchronisation
|
|
$ldap_users[$uid] = self::ldapStamp2UnixStamp(
|
|
$info[$ligne]['modifytimestamp'][0],
|
|
$config_ldap->fields['time_offset']
|
|
);
|
|
$user_infos[$uid]["name"] = $info[$ligne][$login_field][0];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
if (self::isLdapPageSizeAvailable($config_ldap) && version_compare(PHP_VERSION, '7.3') < 0) {
|
|
// phpcs:ignore Generic.PHP.DeprecatedFunctions
|
|
ldap_control_paged_result_response($ds, $sr, $cookie);
|
|
}
|
|
|
|
} while (($cookie !== null) && ($cookie != ''));
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the list of LDAP users to add/synchronize
|
|
*
|
|
* @param array $options possible options:
|
|
* - authldaps_id ID of the server to use
|
|
* - mode user to synchronise or add?
|
|
* - ldap_filter ldap filter to use
|
|
* - basedn force basedn (default authldaps_id one)
|
|
* - order display order
|
|
* - begin_date begin date to time limit
|
|
* - end_date end date to time limit
|
|
* - script true if called by an external script
|
|
* @param array $results result stats
|
|
* @param boolean $limitexceeded limit exceeded exception
|
|
*
|
|
* @return array of the user
|
|
*/
|
|
static function getAllUsers(array $options, &$results, &$limitexceeded) {
|
|
global $DB;
|
|
|
|
$config_ldap = new self();
|
|
$res = $config_ldap->getFromDB($options['authldaps_id']);
|
|
|
|
$values = [
|
|
'order' => 'DESC',
|
|
'mode' => self::ACTION_SYNCHRONIZE,
|
|
'ldap_filter' => '',
|
|
'basedn' => $config_ldap->fields['basedn'],
|
|
'begin_date' => null,
|
|
'end_date' => date('Y-m-d H:i:s', time()-DAY_TIMESTAMP),
|
|
'script' => 0, //Called by an external script or not
|
|
];
|
|
|
|
foreach ($options as $option => $value) {
|
|
// this test break mode detection - if ($value != '') {
|
|
$values[$option] = $value;
|
|
//}
|
|
}
|
|
|
|
$ldap_users = [];
|
|
$user_infos = [];
|
|
$limitexceeded = false;
|
|
|
|
// we prevent some delay...
|
|
if (!$res) {
|
|
return false;
|
|
}
|
|
if ($values['order'] != "DESC") {
|
|
$values['order'] = "ASC";
|
|
}
|
|
$ds = $config_ldap->connect();
|
|
$field_for_sync = $config_ldap->getLdapIdentifierToUse();
|
|
$field_for_db = $config_ldap->getDatabaseIdentifierToUse();
|
|
if ($ds) {
|
|
//Search for ldap login AND modifyTimestamp,
|
|
//which indicates the last update of the object in directory
|
|
$attrs = [$config_ldap->fields['login_field'], "modifyTimestamp"];
|
|
if ($field_for_sync != $config_ldap->fields['login_field']) {
|
|
$attrs[] = $field_for_sync;
|
|
}
|
|
|
|
// Try a search to find the DN
|
|
if ($values['ldap_filter'] == '') {
|
|
$filter = "(".$field_for_sync."=*)";
|
|
if (!empty($config_ldap->fields['condition'])) {
|
|
$filter = "(& $filter ".$config_ldap->fields['condition'].")";
|
|
}
|
|
} else {
|
|
$filter = $values['ldap_filter'];
|
|
}
|
|
|
|
if ($values['script'] && !empty($values['begin_date'])) {
|
|
$filter_timestamp = self::addTimestampRestrictions($values['begin_date'],
|
|
$values['end_date']);
|
|
$filter = "(&$filter $filter_timestamp)";
|
|
}
|
|
$result = self::searchForUsers($ds, $values, $filter, $attrs, $limitexceeded,
|
|
$user_infos, $ldap_users, $config_ldap);
|
|
if (!$result) {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
$glpi_users = [];
|
|
|
|
$select = [
|
|
'FROM' => User::getTable(),
|
|
'ORDER' => ['name ' . $values['order']]
|
|
];
|
|
|
|
if ($values['mode'] != self::ACTION_IMPORT) {
|
|
$select['WHERE'] = [
|
|
'authtype' => [-1, Auth::NOT_YET_AUTHENTIFIED, Auth::LDAP, Auth::EXTERNAL, Auth::CAS],
|
|
'auths_id' => $options['authldaps_id']
|
|
];
|
|
}
|
|
|
|
$iterator = $DB->request($select);
|
|
|
|
while ($user = $iterator->next()) {
|
|
$tmpuser = new User();
|
|
|
|
//Ldap add : fill the array with the login of the user
|
|
if ($values['mode'] == self::ACTION_IMPORT) {
|
|
$glpi_users[$user['name']] = $user['name'];
|
|
} else {
|
|
//Ldap synchronisation : look if the user exists in the directory
|
|
//and compares the modifications dates (ldap and glpi db)
|
|
$userfound = self::dnExistsInLdap($user_infos, $user['user_dn']);
|
|
if (!empty($ldap_users[$user[$field_for_db]]) || $userfound) {
|
|
// userfound seems that user dn is present in GLPI DB but do not correspond to an GLPI user
|
|
// -> renaming case
|
|
if ($userfound) {
|
|
//Get user in DB with this dn
|
|
if (!$tmpuser->getFromDBByDn(Toolbox::addslashes_deep($user['user_dn']))) {
|
|
//This should never happened
|
|
//If a user_dn is present more than one time in database
|
|
//Just skip user synchronization to avoid errors
|
|
continue;
|
|
}
|
|
$glpi_users[] = ['id' => $user['id'],
|
|
'user' => $userfound['name'],
|
|
$field_for_sync => (isset($userfound[$config_ldap->fields['sync_field']]) ? $userfound[$config_ldap->fields['sync_field']] : 'NULL'),
|
|
'timestamp' => $user_infos[$userfound[$field_for_sync]]['timestamp'],
|
|
'date_sync' => $tmpuser->fields['date_sync'],
|
|
'dn' => $user['user_dn']];
|
|
} else if (($values['mode'] == self::ACTION_ALL)
|
|
|| (($ldap_users[$user[$field_for_db]] - strtotime($user['date_sync'])) > 0)) {
|
|
//If entry was modified or if script should synchronize all the users
|
|
$glpi_users[] = ['id' => $user['id'],
|
|
'user' => $user['name'],
|
|
$field_for_sync => $user['sync_field'],
|
|
'timestamp' => $user_infos[$user[$field_for_db]]['timestamp'],
|
|
'date_sync' => $user['date_sync'],
|
|
'dn' => $user['user_dn']];
|
|
}
|
|
|
|
} else if (($values['mode'] == self::ACTION_ALL)
|
|
&& !$limitexceeded) {
|
|
// Only manage deleted user if ALL (because of entity visibility in delegated mode)
|
|
|
|
//If user is marked as coming from LDAP, but is not present in it anymore
|
|
if (!$user['is_deleted']
|
|
&& ($user['auths_id'] == $options['authldaps_id'])) {
|
|
User::manageDeletedUserInLdap($user['id']);
|
|
$results[self::USER_DELETED_LDAP] ++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//If add, do the difference between ldap users and glpi users
|
|
if ($values['mode'] == self::ACTION_IMPORT) {
|
|
$diff = array_diff_ukey($ldap_users, $glpi_users, 'strcasecmp');
|
|
$list = [];
|
|
$tmpuser = new User();
|
|
|
|
foreach ($diff as $user) {
|
|
//If user dn exists in DB, it means that user login field has changed
|
|
if (!$tmpuser->getFromDBByDn(Toolbox::addslashes_deep($user_infos[$user]["user_dn"]))) {
|
|
$entry = ["user" => $user_infos[$user][$config_ldap->fields['login_field']],
|
|
"timestamp" => $user_infos[$user]["timestamp"],
|
|
"date_sync" => Dropdown::EMPTY_VALUE];
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
$entry[$field_for_sync] = $user_infos[$user][$field_for_sync];
|
|
}
|
|
$list[] = $entry;
|
|
}
|
|
}
|
|
if ($values['order'] == 'DESC') {
|
|
rsort($list);
|
|
} else {
|
|
sort($list);
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
return $glpi_users;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if a user DN exists in a ldap user search result
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @param array $ldap_infos ldap user search result
|
|
* @param string $user_dn user dn to look for
|
|
*
|
|
* @return boolean false if the user dn doesn't exist, user ldap infos otherwise
|
|
*/
|
|
static function dnExistsInLdap($ldap_infos, $user_dn) {
|
|
|
|
$found = false;
|
|
foreach ($ldap_infos as $ldap_info) {
|
|
if ($ldap_info['user_dn'] == $user_dn) {
|
|
$found = $ldap_info;
|
|
break;
|
|
}
|
|
}
|
|
return $found;
|
|
}
|
|
|
|
|
|
/**
|
|
* Show LDAP groups to add or synchronize in an entity
|
|
*
|
|
* @param string $target target page for the form
|
|
* @param integer $start where to start the list
|
|
* @param integer $sync synchronize or add? (default 0)
|
|
* @param string $filter ldap filter to use (default '')
|
|
* @param string $filter2 second ldap filter to use (which case?) (default '')
|
|
* @param integer $entity working entity
|
|
* @param string $order display order (default DESC)
|
|
*
|
|
* @return void
|
|
*/
|
|
static function showLdapGroups($target, $start, $sync = 0, $filter = '', $filter2 = '',
|
|
$entity = 0, $order = 'DESC') {
|
|
|
|
echo "<br>";
|
|
$limitexceeded = false;
|
|
$ldap_groups = self::getAllGroups($_SESSION["ldap_server"], $filter, $filter2, $entity,
|
|
$limitexceeded, $order);
|
|
|
|
if (is_array($ldap_groups)) {
|
|
$numrows = count($ldap_groups);
|
|
$rand = mt_rand();
|
|
if ($numrows > 0) {
|
|
self::displaySizeLimitWarning($limitexceeded);
|
|
$parameters = '';
|
|
Html::printPager($start, $numrows, $target, $parameters);
|
|
|
|
// delete end
|
|
array_splice($ldap_groups, $start + $_SESSION['glpilist_limit']);
|
|
// delete begin
|
|
if ($start > 0) {
|
|
array_splice($ldap_groups, 0, $start);
|
|
}
|
|
|
|
echo "<div class='center'>";
|
|
Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
|
|
$massiveactionparams
|
|
= ['num_displayed'
|
|
=> min($_SESSION['glpilist_limit'], count($ldap_groups)),
|
|
'container'
|
|
=> 'mass'.__CLASS__.$rand,
|
|
'specific_actions'
|
|
=> [__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'import_group'
|
|
=> _sx('button', 'Import')],
|
|
'extraparams'
|
|
=> ['massive_action_fields' => ['dn', 'ldap_import_type',
|
|
'ldap_import_entities',
|
|
'ldap_import_recursive']]];
|
|
Html::showMassiveActions($massiveactionparams);
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr>";
|
|
echo "<th width='10'>";
|
|
Html::showCheckbox(['criterion' => ['tag_for_massive' => 'select_item']]);
|
|
echo "</th>";
|
|
$header_num = 0;
|
|
echo Search::showHeaderItem(Search::HTML_OUTPUT, Group::getTypeName(1), $header_num,
|
|
$target."?order=".($order=="DESC"?"ASC":"DESC"),
|
|
1, $order);
|
|
echo "<th>".__('Group DN')."</th>";
|
|
echo "<th>".__('Destination entity')."</th>";
|
|
if (Session::isMultiEntitiesMode()) {
|
|
echo"<th>";
|
|
Html::showCheckbox(['criterion' => ['tag_for_massive' => 'select_item_child_entities']]);
|
|
echo " ".__('Child entities');
|
|
echo "</th>";
|
|
}
|
|
echo "</tr>";
|
|
|
|
$dn_index = 0;
|
|
foreach ($ldap_groups as $groupinfos) {
|
|
$group = $groupinfos["cn"];
|
|
$group_dn = $groupinfos["dn"];
|
|
$search_type = $groupinfos["search_type"];
|
|
|
|
echo "<tr class='tab_bg_2 center'>";
|
|
echo "<td>";
|
|
echo Html::hidden("dn[$dn_index]", ['value' => $group_dn,
|
|
'data-glpicore-ma-tags' => 'common']);
|
|
echo Html::hidden("ldap_import_type[$dn_index]", ['value' => $search_type,
|
|
'data-glpicore-ma-tags' => 'common']);
|
|
Html::showMassiveActionCheckBox(__CLASS__, $dn_index,
|
|
['massive_tags' => 'select_item']);
|
|
echo "</td>";
|
|
echo "<td>" . $group . "</td>";
|
|
echo "<td>" .$group_dn. "</td>";
|
|
echo "<td>";
|
|
Entity::dropdown(['value' => $entity,
|
|
'name' => "ldap_import_entities[$dn_index]",
|
|
'specific_tags' => ['data-glpicore-ma-tags' => 'common']]);
|
|
echo "</td>";
|
|
if (Session::isMultiEntitiesMode()) {
|
|
echo "<td>";
|
|
Html::showMassiveActionCheckBox(__CLASS__, $dn_index,
|
|
['massive_tags' => 'select_item_child_entities',
|
|
'name' => "ldap_import_recursive[$dn_index]",
|
|
'specific_tags' => ['data-glpicore-ma-tags' => 'entities_id']]);
|
|
echo "</td>";
|
|
} else {
|
|
echo Html::hidden("ldap_import_recursive[$dn_index]", ['value' => 0,
|
|
'data-glpicore-ma-tags' => 'entities_id']);
|
|
}
|
|
echo "</tr>\n";
|
|
$dn_index++;
|
|
}
|
|
|
|
$massiveactionparams['ontop'] = false;
|
|
Html::showMassiveActions($massiveactionparams);
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
Html::printPager($start, $numrows, $target, $parameters);
|
|
|
|
} else {
|
|
echo "<div class='center b'>" . __('No group to be imported') . "</div>";
|
|
}
|
|
} else {
|
|
echo "<div class='center b'>" . __('No group to be imported') . "</div>";
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all LDAP groups from a ldap server which are not already in an entity
|
|
*
|
|
* @since 0.84 new parameter $limitexceeded
|
|
*
|
|
* @param integer $auths_id ID of the server to use
|
|
* @param string $filter ldap filter to use
|
|
* @param string $filter2 second ldap filter to use if needed
|
|
* @param string $entity entity to search
|
|
* @param boolean $limitexceeded is limit exceeded
|
|
* @param string $order order to use (default DESC)
|
|
*
|
|
* @return array of the groups
|
|
*/
|
|
static function getAllGroups($auths_id, $filter, $filter2, $entity, &$limitexceeded,
|
|
$order = 'DESC') {
|
|
global $DB;
|
|
|
|
$config_ldap = new self();
|
|
$config_ldap->getFromDB($auths_id);
|
|
$infos = [];
|
|
$groups = [];
|
|
|
|
$ds = $config_ldap->connect();
|
|
if ($ds) {
|
|
switch ($config_ldap->fields["group_search_type"]) {
|
|
case self::GROUP_SEARCH_USER:
|
|
$infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter,
|
|
$limitexceeded, false, $infos);
|
|
break;
|
|
|
|
case self::GROUP_SEARCH_GROUP:
|
|
$infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter,
|
|
$limitexceeded, true, $infos);
|
|
break;
|
|
|
|
case self::GROUP_SEARCH_BOTH:
|
|
$infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter,
|
|
$limitexceeded, true, $infos);
|
|
$infos = self::getGroupsFromLDAP($ds, $config_ldap, $filter2,
|
|
$limitexceeded, false, $infos);
|
|
break;
|
|
}
|
|
if (!empty($infos)) {
|
|
$glpi_groups = [];
|
|
|
|
//Get all groups from GLPI DB for the current entity and the subentities
|
|
$iterator = $DB->request([
|
|
'SELECT' => ['ldap_group_dn','ldap_value'],
|
|
'FROM' => 'glpi_groups',
|
|
'WHERE' => getEntitiesRestrictCriteria('glpi_groups')
|
|
]);
|
|
|
|
//If the group exists in DB -> unset it from the LDAP groups
|
|
while ($group = $iterator->next()) {
|
|
//use DN for next step
|
|
//depending on the type of search when groups are imported
|
|
//the DN may be in two separate fields
|
|
if (isset($group["ldap_group_dn"]) && !empty($group["ldap_group_dn"])) {
|
|
$glpi_groups[$group["ldap_group_dn"]] = 1;
|
|
} else if (isset($group["ldap_value"]) && !empty($group["ldap_value"])) {
|
|
$glpi_groups[$group["ldap_value"]] = 1;
|
|
}
|
|
}
|
|
$ligne = 0;
|
|
|
|
foreach ($infos as $dn => $info) {
|
|
//reconcile by DN
|
|
if (!isset($glpi_groups[$dn])) {
|
|
$groups[$ligne]["dn"] = $dn;
|
|
$groups[$ligne]["cn"] = $info["cn"];
|
|
$groups[$ligne]["search_type"] = $info["search_type"];
|
|
$ligne++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($order == 'DESC') {
|
|
function local_cmp($b, $a) {
|
|
return strcasecmp($a['cn'], $b['cn']);
|
|
}
|
|
|
|
} else {
|
|
function local_cmp($a, $b) {
|
|
return strcasecmp($a['cn'], $b['cn']);
|
|
}
|
|
}
|
|
usort($groups, 'local_cmp');
|
|
|
|
}
|
|
return $groups;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the group's cn by giving his DN
|
|
*
|
|
* @param resource $ldap_connection ldap connection to use
|
|
* @param string $group_dn the group's dn
|
|
*
|
|
* @return string the group cn
|
|
*/
|
|
static function getGroupCNByDn($ldap_connection, $group_dn) {
|
|
|
|
$sr = @ ldap_read($ldap_connection, $group_dn, "objectClass=*", ["cn"]);
|
|
if ($sr === false) {
|
|
//group does not exists
|
|
return false;
|
|
}
|
|
$v = self::get_entries_clean($ldap_connection, $sr);
|
|
if (!is_array($v) || (count($v) == 0) || empty($v[0]["cn"][0])) {
|
|
return false;
|
|
}
|
|
return $v[0]["cn"][0];
|
|
}
|
|
|
|
|
|
/**
|
|
* Set groups from ldap
|
|
*
|
|
* @since 0.84 new parameter $limitexceeded
|
|
*
|
|
* @param resource $ldap_connection LDAP connection
|
|
* @param object $config_ldap LDAP configuration
|
|
* @param string $filter Filters
|
|
* @param boolean $limitexceeded Is limit exceeded
|
|
* @param boolean $search_in_groups Search in groups (true by default)
|
|
* @param array $groups Groups to search
|
|
*
|
|
* @return array
|
|
*/
|
|
static function getGroupsFromLDAP($ldap_connection, $config_ldap, $filter,
|
|
&$limitexceeded, $search_in_groups = true,
|
|
$groups = []) {
|
|
global $DB;
|
|
|
|
//First look for groups in group objects
|
|
$extra_attribute = ($search_in_groups?"cn":$config_ldap->fields["group_field"]);
|
|
$attrs = ["dn", $extra_attribute];
|
|
|
|
if ($filter == '') {
|
|
if ($search_in_groups) {
|
|
$filter = (!empty($config_ldap->fields['group_condition'])
|
|
? $config_ldap->fields['group_condition'] : "(objectclass=*)");
|
|
} else {
|
|
$filter = (!empty($config_ldap->fields['condition'])
|
|
? $config_ldap->fields['condition'] : "(objectclass=*)");
|
|
}
|
|
}
|
|
$cookie = '';
|
|
$count = 0;
|
|
do {
|
|
$filter = Toolbox::unclean_cross_side_scripting_deep(Toolbox::stripslashes_deep($filter));
|
|
if (self::isLdapPageSizeAvailable($config_ldap)) {
|
|
if (version_compare(PHP_VERSION, '7.3') < 0) {
|
|
//prior to PHP 7.3, use ldap_control_paged_result
|
|
// phpcs:ignore Generic.PHP.DeprecatedFunctions
|
|
ldap_control_paged_result($ldap_connection, $config_ldap->fields['pagesize'], true, $cookie);
|
|
$sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs);
|
|
} else {
|
|
//since PHP 7.3, send serverctrls to ldap_search
|
|
$controls = [
|
|
[
|
|
'oid' =>LDAP_CONTROL_PAGEDRESULTS,
|
|
'iscritical' => true,
|
|
'value' => [
|
|
'size' => $config_ldap->fields['pagesize'],
|
|
'cookie' => $cookie
|
|
]
|
|
]
|
|
];
|
|
$sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
|
|
ldap_parse_result($ldap_connection, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls);
|
|
if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) {
|
|
$cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'];
|
|
} else {
|
|
$cookie = '';
|
|
}
|
|
}
|
|
} else {
|
|
$sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs);
|
|
}
|
|
|
|
if ($sr) {
|
|
if (in_array(ldap_errno($ldap_connection), [4,11])) {
|
|
// openldap return 4 for Size limit exceeded
|
|
$limitexceeded = true;
|
|
}
|
|
|
|
$infos = self::get_entries_clean($ldap_connection, $sr);
|
|
if (in_array(ldap_errno($ldap_connection), [4,11])) {
|
|
// openldap return 4 for Size limit exceeded
|
|
$limitexceeded = true;
|
|
}
|
|
|
|
$count += $infos['count'];
|
|
//If page results are enabled and the number of results is greater than the maximum allowed
|
|
//warn user that limit is exceeded and stop search
|
|
if (self::isLdapPageSizeAvailable($config_ldap)
|
|
&& $config_ldap->fields['ldap_maxlimit']
|
|
&& ($count > $config_ldap->fields['ldap_maxlimit'])) {
|
|
$limitexceeded = true;
|
|
break;
|
|
}
|
|
|
|
for ($ligne=0; $ligne < $infos["count"]; $ligne++) {
|
|
if ($search_in_groups) {
|
|
// No cn : not a real object
|
|
if (isset($infos[$ligne]["cn"][0])) {
|
|
$groups[$infos[$ligne]["dn"]] = (["cn" => $infos[$ligne]["cn"][0],
|
|
"search_type" => "groups"]);
|
|
}
|
|
|
|
} else {
|
|
if (isset($infos[$ligne][$extra_attribute])) {
|
|
if (($config_ldap->fields["group_field"] == 'dn')
|
|
|| in_array('ou', $groups)) {
|
|
$dn = $infos[$ligne][$extra_attribute];
|
|
$ou = [];
|
|
for ($tmp=$dn; count($tmptab = explode(',', $tmp, 2))==2; $tmp=$tmptab[1]) {
|
|
$ou[] = $tmptab[1];
|
|
}
|
|
|
|
/// Search in DB for group with ldap_group_dn
|
|
if (($config_ldap->fields["group_field"] == 'dn')
|
|
&& (count($ou) > 0)) {
|
|
$iterator = $DB->request([
|
|
'SELECT' => ['ldap_value'],
|
|
'FROM' => 'glpi_groups',
|
|
'WHERE' => [
|
|
'ldap_group_dn' => Toolbox::addslashes_deep($ou)
|
|
]
|
|
]);
|
|
|
|
while ($group = $iterator->next()) {
|
|
$groups[$group['ldap_value']] = ["cn" => $group['ldap_value'],
|
|
"search_type" => "users"];
|
|
}
|
|
}
|
|
|
|
} else {
|
|
for ($ligne_extra=0; $ligne_extra<$infos[$ligne][$extra_attribute]["count"];
|
|
$ligne_extra++) {
|
|
$groups[$infos[$ligne][$extra_attribute][$ligne_extra]]
|
|
= ["cn" => self::getGroupCNByDn($ldap_connection,
|
|
$infos[$ligne][$extra_attribute][$ligne_extra]),
|
|
"search_type"
|
|
=> "users"];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (self::isLdapPageSizeAvailable($config_ldap) && version_compare(PHP_VERSION, '7.3') < 0) {
|
|
// phpcs:ignore Generic.PHP.DeprecatedFunctions
|
|
ldap_control_paged_result_response($ldap_connection, $sr, $cookie);
|
|
}
|
|
} while (($cookie !== null) && ($cookie != ''));
|
|
|
|
return $groups;
|
|
}
|
|
|
|
|
|
/**
|
|
* Form to choose a ldap server
|
|
*
|
|
* @param string $target target page for the form
|
|
*
|
|
* @return void
|
|
*/
|
|
static function ldapChooseDirectory($target) {
|
|
global $DB;
|
|
|
|
$iterator = $DB->request([
|
|
'FROM' => self::getTable(),
|
|
'WHERE' => [
|
|
'is_active' => 1
|
|
],
|
|
'ORDER' => 'name ASC'
|
|
]);
|
|
|
|
if (count($iterator) == 1) {
|
|
//If only one server, do not show the choose ldap server window
|
|
$ldap = $iterator->next();
|
|
$_SESSION["ldap_server"] = $ldap["id"];
|
|
Html::redirect($_SERVER['PHP_SELF']);
|
|
}
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form action='$target' method=\"post\">";
|
|
echo "<p>" . __('Please choose LDAP directory to import users and groups from') . "</p>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr class='tab_bg_2'><th colspan='2'>" . __('LDAP directory choice') . "</th></tr>";
|
|
|
|
//If more than one ldap server
|
|
if (count($iterator) > 1) {
|
|
echo "<tr class='tab_bg_2'><td class='center'>" . __('Name') . "</td>";
|
|
echo "<td class='center'>";
|
|
AuthLDAP::Dropdown(['name' => 'ldap_server',
|
|
'display_emptychoice' => false,
|
|
'comment' => true,
|
|
'condition' => ['is_active' => 1]]);
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td class='center' colspan='2'>";
|
|
echo "<input class='submit' type='submit' name='ldap_showusers' value=\"".
|
|
_sx('button', 'Post') . "\"></td></tr>";
|
|
|
|
} else {
|
|
//No ldap server
|
|
echo "<tr class='tab_bg_2'>".
|
|
"<td class='center' colspan='2'>".__('No LDAP directory defined in GLPI')."</td></tr>";
|
|
}
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
/**
|
|
* Force synchronization for one user
|
|
*
|
|
* @param User $user User to synchronize
|
|
* @param boolean $display Display message information on redirect (true by default)
|
|
*
|
|
* @return array|boolean with state, else false
|
|
*/
|
|
static function forceOneUserSynchronization(User $user, $display = true) {
|
|
$authldap = new AuthLDAP();
|
|
|
|
//Get the LDAP server from which the user has been imported
|
|
if ($authldap->getFromDB($user->fields['auths_id'])) {
|
|
$user_field = 'name';
|
|
$id_field = $authldap->fields['login_field'];
|
|
if ($authldap->isSyncFieldEnabled() && !empty($user->fields['sync_field'])) {
|
|
$user_field = 'sync_field';
|
|
$id_field = $authldap->fields['sync_field'];
|
|
}
|
|
return AuthLDAP::ldapImportUserByServerId(
|
|
[
|
|
'method' => self::IDENTIFIER_LOGIN,
|
|
'value' => $user->fields[$user_field],
|
|
'identifier_field' => $id_field,
|
|
'user_field' => $user_field
|
|
],
|
|
true,
|
|
$user->fields["auths_id"],
|
|
$display
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Import a user from a specific ldap server
|
|
*
|
|
* @param array $params of parameters: method (IDENTIFIER_LOGIN or IDENTIFIER_EMAIL) + value
|
|
* @param boolean $action synchoronize (true) or import (false)
|
|
* @param integer $ldap_server ID of the LDAP server to use
|
|
* @param boolean $display display message information on redirect (false by default)
|
|
*
|
|
* @return array|boolean with state, else false
|
|
*/
|
|
static function ldapImportUserByServerId(array $params, $action, $ldap_server,
|
|
$display = false) {
|
|
|
|
$params = Toolbox::stripslashes_deep($params);
|
|
$config_ldap = new self();
|
|
$res = $config_ldap->getFromDB($ldap_server);
|
|
$input = [];
|
|
|
|
// we prevent some delay...
|
|
if (!$res) {
|
|
return false;
|
|
}
|
|
|
|
if (!isset($params['identifier_field'])) {
|
|
$params['identifier_field'] = $config_ldap->getLdapIdentifierToUse();
|
|
}
|
|
if (!isset($params['user_field'])) {
|
|
$params['user_field'] = $config_ldap->getDatabaseIdentifierToUse();
|
|
}
|
|
|
|
$search_parameters = [];
|
|
//Connect to the directory
|
|
if (isset(self::$conn_cache[$ldap_server])) {
|
|
$ds = self::$conn_cache[$ldap_server];
|
|
} else {
|
|
$ds = $config_ldap->connect();
|
|
}
|
|
if ($ds) {
|
|
self::$conn_cache[$ldap_server] = $ds;
|
|
$search_parameters['method'] = $params['method'];
|
|
$search_parameters['fields'][self::IDENTIFIER_LOGIN] = $params['identifier_field'];
|
|
|
|
if ($params['method'] == self::IDENTIFIER_EMAIL) {
|
|
$search_parameters['fields'][self::IDENTIFIER_EMAIL]
|
|
= $config_ldap->fields['email1_field'];
|
|
}
|
|
|
|
//Get the user's dn & login
|
|
$attribs = ['basedn' => $config_ldap->fields['basedn'],
|
|
'login_field' => $search_parameters['fields'][$search_parameters['method']],
|
|
'search_parameters' => $search_parameters,
|
|
'user_params' => $params,
|
|
'condition' => $config_ldap->fields['condition']];
|
|
|
|
try {
|
|
$infos = self::searchUserDn($ds, $attribs);
|
|
|
|
if ($infos && $infos['dn']) {
|
|
$user_dn = $infos['dn'];
|
|
$user = new User();
|
|
|
|
$login = self::getFieldValue($infos, $search_parameters['fields'][$search_parameters['method']]);
|
|
|
|
//Get information from LDAP
|
|
if ($user->getFromLDAP($ds, $config_ldap->fields, $user_dn, addslashes($login),
|
|
($action == self::ACTION_IMPORT))) {
|
|
// Add the auth method
|
|
// Force date sync
|
|
$user->fields["date_sync"] = $_SESSION["glpi_currenttime"];
|
|
$user->fields['is_deleted_ldap'] = 0;
|
|
|
|
//Save information in database !
|
|
$input = $user->fields;
|
|
|
|
//clean picture from input
|
|
// (picture managed in User::post_addItem and prepareInputForUpdate)
|
|
unset($input['picture']);
|
|
|
|
if ($action == self::ACTION_IMPORT) {
|
|
$input["authtype"] = Auth::LDAP;
|
|
$input["auths_id"] = $ldap_server;
|
|
// Display message after redirect
|
|
if ($display) {
|
|
$input['add'] = 1;
|
|
}
|
|
|
|
$user->fields["id"] = $user->add($input);
|
|
return ['action' => self::USER_IMPORTED,
|
|
'id' => $user->fields["id"]];
|
|
}
|
|
//Get the ID by user name
|
|
if (!($id = User::getIdByfield($params['user_field'], $login))) {
|
|
//In case user id as changed : get id by dn
|
|
$id = User::getIdByfield('user_dn', $user_dn);
|
|
}
|
|
$input['id'] = $id;
|
|
|
|
if ($display) {
|
|
$input['update'] = 1;
|
|
}
|
|
$user->update($input);
|
|
return ['action' => self::USER_SYNCHRONIZED,
|
|
'id' => $input['id']];
|
|
}
|
|
return false;
|
|
|
|
}
|
|
if ($action != self::ACTION_IMPORT) {
|
|
$users_id = User::getIdByField($params['user_field'], $params['value']);
|
|
User::manageDeletedUserInLdap($users_id);
|
|
return ['action' => self::USER_DELETED_LDAP,
|
|
'id' => $users_id];
|
|
}
|
|
} catch (\RuntimeException $e) {
|
|
Toolbox::logError($e->getMessage());
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Import grousp from an LDAP directory
|
|
*
|
|
* @param string $group_dn dn of the group to import
|
|
* @param array $options array for
|
|
* - authldaps_id
|
|
* - entities_id where group must to be imported
|
|
* - is_recursive
|
|
*
|
|
* @return integer|false
|
|
*/
|
|
static function ldapImportGroup($group_dn, $options = []) {
|
|
|
|
$config_ldap = new self();
|
|
$res = $config_ldap->getFromDB($options['authldaps_id']);
|
|
|
|
// we prevent some delay...
|
|
if (!$res) {
|
|
return false;
|
|
}
|
|
|
|
//Connect to the directory
|
|
$ds = $config_ldap->connect();
|
|
if ($ds) {
|
|
$group_infos = self::getGroupByDn($ds, stripslashes($group_dn));
|
|
$group = new Group();
|
|
if ($options['type'] == "groups") {
|
|
return $group->add(["name" => addslashes($group_infos["cn"][0]),
|
|
"ldap_group_dn" => addslashes($group_infos["dn"]),
|
|
"entities_id" => $options['entities_id'],
|
|
"is_recursive" => $options['is_recursive']]);
|
|
}
|
|
return $group->add(["name" => addslashes($group_infos["cn"][0]),
|
|
"ldap_field" => $config_ldap->fields["group_field"],
|
|
"ldap_value" => addslashes($group_infos["dn"]),
|
|
"entities_id" => $options['entities_id'],
|
|
"is_recursive" => $options['is_recursive']]);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Open LDAP connection to current server
|
|
*
|
|
* @return resource|boolean
|
|
*/
|
|
function connect() {
|
|
|
|
return $this->connectToServer($this->fields['host'], $this->fields['port'],
|
|
$this->fields['rootdn'],
|
|
Toolbox::sodiumDecrypt($this->fields['rootdn_passwd']),
|
|
$this->fields['use_tls'],
|
|
$this->fields['deref_option']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Connect to a LDAP server
|
|
*
|
|
* @param string $host LDAP host to connect
|
|
* @param string $port port to use
|
|
* @param string $login login to use (default '')
|
|
* @param string $password password to use (default '')
|
|
* @param boolean $use_tls use a TLS connection? (false by default)
|
|
* @param integer $deref_options deref options used
|
|
*
|
|
* @return resource link to the LDAP server : false if connection failed
|
|
*/
|
|
static function connectToServer($host, $port, $login = "", $password = "",
|
|
$use_tls = false, $deref_options = 0) {
|
|
|
|
$ds = @ldap_connect($host, intval($port));
|
|
if ($ds) {
|
|
@ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
|
|
@ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
|
|
@ldap_set_option($ds, LDAP_OPT_DEREF, $deref_options);
|
|
if ($use_tls) {
|
|
if (!@ldap_start_tls($ds)) {
|
|
return false;
|
|
}
|
|
}
|
|
// Auth bind
|
|
if ($login != '') {
|
|
$b = @ldap_bind($ds, $login, $password);
|
|
} else { // Anonymous bind
|
|
$b = @ldap_bind($ds);
|
|
}
|
|
if ($b) {
|
|
return $ds;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Try to connect to a ldap server
|
|
*
|
|
* @param array $ldap_method ldap_method array to use
|
|
* @param string $login User Login
|
|
* @param string $password User Password
|
|
*
|
|
* @return resource|boolean link to the LDAP server : false if connection failed
|
|
*/
|
|
static function tryToConnectToServer($ldap_method, $login, $password) {
|
|
if (!function_exists('ldap_connect')) {
|
|
Toolbox::logError("ldap_connect function is missing. Did you miss install php-ldap extension?");
|
|
return false;
|
|
}
|
|
$ds = self::connectToServer($ldap_method['host'], $ldap_method['port'],
|
|
$ldap_method['rootdn'],
|
|
Toolbox::sodiumDecrypt($ldap_method['rootdn_passwd']),
|
|
$ldap_method['use_tls'], $ldap_method['deref_option']);
|
|
|
|
// Test with login and password of the user if exists
|
|
if (!$ds
|
|
&& !empty($login)) {
|
|
$ds = self::connectToServer($ldap_method['host'], $ldap_method['port'], $login,
|
|
$password, $ldap_method['use_tls'],
|
|
$ldap_method['deref_option']);
|
|
}
|
|
|
|
//If connection is not successful on this directory, try replicates (if replicates exists)
|
|
if (!$ds
|
|
&& ($ldap_method['id'] > 0)) {
|
|
foreach (self::getAllReplicateForAMaster($ldap_method['id']) as $replicate) {
|
|
$ds = self::connectToServer($replicate["host"], $replicate["port"],
|
|
$ldap_method['rootdn'],
|
|
Toolbox::sodiumDecrypt($ldap_method['rootdn_passwd']),
|
|
$ldap_method['use_tls'], $ldap_method['deref_option']);
|
|
|
|
// Test with login and password of the user
|
|
if (!$ds
|
|
&& !empty($login)) {
|
|
$ds = self::connectToServer($replicate["host"], $replicate["port"], $login,
|
|
$password, $ldap_method['use_tls'],
|
|
$ldap_method['deref_option']);
|
|
}
|
|
if ($ds) {
|
|
return $ds;
|
|
}
|
|
}
|
|
}
|
|
return $ds;
|
|
}
|
|
|
|
/**
|
|
* Get LDAP servers
|
|
*
|
|
* @return array
|
|
*/
|
|
static function getLdapServers() {
|
|
return getAllDataFromTable('glpi_authldaps', ['ORDER' => 'is_default DESC']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Is the LDAP authentication used?
|
|
*
|
|
* @return boolean
|
|
*/
|
|
static function useAuthLdap() {
|
|
return (countElementsInTable('glpi_authldaps', ['is_active' => 1]) > 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Import a user from ldap
|
|
* Check all the directories. When the user is found, then import it
|
|
*
|
|
* @param array $options array containing condition:
|
|
* array('name'=>'glpi') or array('email' => 'test at test.com')
|
|
*
|
|
* @return array|boolean false if fail
|
|
*/
|
|
static function importUserFromServers($options = []) {
|
|
|
|
$auth = new Auth();
|
|
$params = [];
|
|
if (isset($options['name'])) {
|
|
$params['value'] = $options['name'];
|
|
$params['method'] = self::IDENTIFIER_LOGIN;
|
|
}
|
|
if (isset($options['email'])) {
|
|
$params['value'] = $options['email'];
|
|
$params['method'] = self::IDENTIFIER_EMAIL;
|
|
}
|
|
|
|
$auth->user_present = $auth->userExists($options);
|
|
|
|
//If the user does not exists
|
|
if ($auth->user_present == 0) {
|
|
$auth->getAuthMethods();
|
|
$ldap_methods = $auth->authtypes["ldap"];
|
|
|
|
foreach ($ldap_methods as $ldap_method) {
|
|
if ($ldap_method['is_active']) {
|
|
//we're looking for a user login
|
|
$params['identifier_field'] = $ldap_method['login_field'];
|
|
$params['user_field'] = 'name';
|
|
$result = self::ldapImportUserByServerId($params, 0, $ldap_method["id"], true);
|
|
if ($result != false) {
|
|
return $result;
|
|
}
|
|
}
|
|
}
|
|
Session::addMessageAfterRedirect(__('User not found or several users found'), false, ERROR);
|
|
|
|
} else {
|
|
Session::addMessageAfterRedirect(__('Unable to add. The user already exist.'), false,
|
|
ERROR);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Authentify a user by checking a specific directory
|
|
*
|
|
* @param object $auth identification object
|
|
* @param string $login user login
|
|
* @param string $password user password
|
|
* @param array $ldap_method ldap_method array to use
|
|
* @param string $user_dn user LDAP DN if present
|
|
*
|
|
* @return object identification object
|
|
*/
|
|
static function ldapAuth($auth, $login, $password, $ldap_method, $user_dn) {
|
|
|
|
$oldlevel = error_reporting(0);
|
|
|
|
$infos = $auth->connection_ldap($ldap_method, $login, $password);
|
|
$user_dn = $infos['dn'];
|
|
$user_sync = (isset($infos['sync_field']) ? $infos['sync_field'] : null);
|
|
|
|
error_reporting($oldlevel);
|
|
|
|
$auth->auth_succeded = false;
|
|
$auth->extauth = 1;
|
|
|
|
if ($user_dn) {
|
|
$auth->auth_succeded = true;
|
|
// try by login+auth_id and next by dn
|
|
if ($auth->user->getFromDBbyNameAndAuth($login, Auth::LDAP, $ldap_method['id'])
|
|
|| $auth->user->getFromDBbyDn(Toolbox::addslashes_deep($user_dn))) {
|
|
//There's already an existing user in DB with the same DN but its login field has changed
|
|
$auth->user->fields['name'] = $login;
|
|
$auth->user_present = true;
|
|
$auth->user_dn = $user_dn;
|
|
} else if ($user_sync !== null && $auth->user->getFromDBbySyncField($user_sync)) {
|
|
//user login/dn have changed
|
|
$auth->user->fields['name'] = $login;
|
|
$auth->user->fields['user_dn'] = $user_dn;
|
|
$auth->user_present = true;
|
|
$auth->user_dn = $user_dn;
|
|
} else { // The user is a new user
|
|
$auth->user_present = false;
|
|
}
|
|
$auth->user->getFromLDAP($auth->ldap_connection, $ldap_method, $user_dn, $login,
|
|
!$auth->user_present);
|
|
$auth->user->fields["authtype"] = Auth::LDAP;
|
|
$auth->user->fields["auths_id"] = $ldap_method["id"];
|
|
}
|
|
return $auth;
|
|
}
|
|
|
|
|
|
/**
|
|
* Try to authentify a user by checking all the directories
|
|
*
|
|
* @param object $auth identification object
|
|
* @param string $login user login
|
|
* @param string $password user password
|
|
* @param integer $auths_id auths_id already used for the user (default 0)
|
|
* @param boolean $user_dn user LDAP DN if present (false by default)
|
|
* @param boolean $break if user is not found in the first directory,
|
|
* continue searching on the following ones (true by default)
|
|
*
|
|
* @return object identification object
|
|
*/
|
|
static function tryLdapAuth($auth, $login, $password, $auths_id = 0, $user_dn = false, $break = true) {
|
|
|
|
//If no specific source is given, test all ldap directories
|
|
if ($auths_id <= 0) {
|
|
foreach ($auth->authtypes["ldap"] as $ldap_method) {
|
|
if ($ldap_method['is_active']) {
|
|
$auth = self::ldapAuth($auth, $login, $password, $ldap_method, $user_dn);
|
|
|
|
if ($auth->auth_succeded
|
|
&& $break) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (array_key_exists($auths_id, $auth->authtypes["ldap"])) {
|
|
// Check if the ldap server indicated as the last good one still exists !
|
|
//A specific ldap directory is given, test it and only this one !
|
|
$auth = self::ldapAuth($auth, $login, $password, $auth->authtypes["ldap"][$auths_id],
|
|
$user_dn);
|
|
}
|
|
return $auth;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get dn for a user
|
|
*
|
|
* @param resource $ds LDAP link
|
|
* @param array $options array of possible options:
|
|
* - basedn : base dn used to search
|
|
* - login_field : attribute to store login
|
|
* - search_parameters array of search parameters
|
|
* - user_params array of parameters : method (IDENTIFIER_LOGIN or IDENTIFIER_EMAIL) + value
|
|
* - condition : ldap condition used
|
|
*
|
|
* @return array|boolean dn of the user, else false
|
|
* @throws \RuntimeException
|
|
*/
|
|
static function searchUserDn($ds, $options = []) {
|
|
|
|
$values = [
|
|
'basedn' => '',
|
|
'login_field' => '',
|
|
'search_parameters' => [],
|
|
'user_params' => '',
|
|
'condition' => '',
|
|
'user_dn' => false,
|
|
];
|
|
|
|
foreach ($options as $key => $value) {
|
|
$values[$key] = $value;
|
|
}
|
|
|
|
//By default authenticate users by login
|
|
$login_attr = $values['search_parameters']['fields'][self::IDENTIFIER_LOGIN];
|
|
$sync_attr = (isset($values['search_parameters']['fields']['sync_field'])) ?
|
|
$values['search_parameters']['fields']['sync_field'] : null;
|
|
|
|
$ldap_parameters = ["dn"];
|
|
foreach ($values['search_parameters']['fields'] as $parameter) {
|
|
$ldap_parameters[] = $parameter;
|
|
}
|
|
|
|
//First : if a user dn is provided, look for it in the directory
|
|
//Before trying to find the user using his login_field
|
|
if ($values['user_dn']) {
|
|
$info = self::getUserByDn($ds, $values['user_dn'], $ldap_parameters);
|
|
|
|
if ($info) {
|
|
$ret = [
|
|
'dn' => $values['user_dn'],
|
|
$login_attr => $info[$login_attr][0]
|
|
];
|
|
if ($sync_attr !== null && isset($info[0][$sync_attr])) {
|
|
$ret['sync_field'] = self::getFieldValue($info[0], $sync_attr);
|
|
}
|
|
return $ret;
|
|
}
|
|
}
|
|
|
|
// Try a search to find the DN
|
|
$filter_value = $values['user_params']['value'];
|
|
if ($values['login_field'] == 'objectguid' && self::isValidGuid($filter_value)) {
|
|
$filter_value = self::guidToHex($filter_value);
|
|
}
|
|
$filter = "(".$values['login_field']."=".$filter_value.")";
|
|
|
|
if (!empty($values['condition'])) {
|
|
$filter = "(& $filter ".$values['condition'].")";
|
|
}
|
|
|
|
if ($result = @ldap_search($ds, $values['basedn'], $filter, $ldap_parameters)) {
|
|
//search has been done, let's check for found results
|
|
$info = self::get_entries_clean($ds, $result);
|
|
|
|
if (is_array($info) && ($info['count'] == 1)) {
|
|
$ret = [
|
|
'dn' => $info[0]['dn'],
|
|
$login_attr => $info[0][$login_attr][0]
|
|
];
|
|
if ($sync_attr !== null && isset($info[0][$sync_attr])) {
|
|
$ret['sync_field'] = self::getFieldValue($info[0], $sync_attr);
|
|
}
|
|
return $ret;
|
|
}
|
|
return false;
|
|
}
|
|
throw new \RuntimeException('Something went wrong searching in LDAP directory');
|
|
}
|
|
|
|
|
|
/**
|
|
* Get an object from LDAP by giving his DN
|
|
*
|
|
* @param resource $ds the active connection to the directory
|
|
* @param string $condition the LDAP filter to use for the search
|
|
* @param string $dn DN of the object
|
|
* @param array $attrs Array of the attributes to retrieve
|
|
* @param boolean $clean (true by default)
|
|
*
|
|
* @return array|boolean false if failed
|
|
*/
|
|
static function getObjectByDn($ds, $condition, $dn, $attrs = [], $clean = true) {
|
|
if ($result = @ ldap_read($ds, $dn, $condition, $attrs)) {
|
|
if ($clean) {
|
|
$info = self::get_entries_clean($ds, $result);
|
|
} else {
|
|
$info = ldap_get_entries($ds, $result);
|
|
}
|
|
if (is_array($info) && ($info['count'] == 1)) {
|
|
return $info[0];
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get user by domain name
|
|
*
|
|
* @param resource $ds the active connection to the directory
|
|
* @param string $user_dn domain name
|
|
* @param array $attrs attributes
|
|
* @param boolean $clean (true by default)
|
|
*
|
|
* @return array|boolean false if failed
|
|
*/
|
|
static function getUserByDn($ds, $user_dn, $attrs, $clean = true) {
|
|
return self::getObjectByDn($ds, "objectClass=*", $user_dn, $attrs, $clean);
|
|
}
|
|
|
|
/**
|
|
* Get infos for groups
|
|
*
|
|
* @param resource $ds LDAP link
|
|
* @param string $group_dn dn of the group
|
|
*
|
|
* @return array|boolean group infos if found, else false
|
|
*/
|
|
static function getGroupByDn($ds, $group_dn) {
|
|
return self::getObjectByDn($ds, "objectClass=*", $group_dn, ["cn"]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Manage values stored in session
|
|
*
|
|
* @param array $options Options
|
|
* @param boolean $delete (false by default)
|
|
*
|
|
* @return void
|
|
*/
|
|
static function manageValuesInSession($options = [], $delete = false) {
|
|
|
|
$fields = ['action', 'authldaps_id', 'basedn', 'begin_date', 'criterias', 'end_date',
|
|
'entities_id', 'interface', 'ldap_filter', 'mode'];
|
|
|
|
//If form accessed via modal, do not show expert mode link
|
|
// Manage new value is set : entity or mode
|
|
if (isset($options['entity'])
|
|
|| isset($options['mode'])) {
|
|
if (isset($options['_in_modal']) && $options['_in_modal']) {
|
|
//If coming form the helpdesk form : reset all criterias
|
|
$_SESSION['ldap_import']['_in_modal'] = 1;
|
|
$_SESSION['ldap_import']['no_expert_mode'] = 1;
|
|
$_SESSION['ldap_import']['action'] = 'show';
|
|
$_SESSION['ldap_import']['interface'] = self::SIMPLE_INTERFACE;
|
|
$_SESSION['ldap_import']['mode'] = self::ACTION_IMPORT;
|
|
} else {
|
|
$_SESSION['ldap_import']['_in_modal'] = 0;
|
|
$_SESSION['ldap_import']['no_expert_mode'] = 0;
|
|
}
|
|
}
|
|
|
|
if (!$delete) {
|
|
|
|
if (!isset($_SESSION['ldap_import']['entities_id'])) {
|
|
$options['entities_id'] = $_SESSION['glpiactive_entity'];
|
|
}
|
|
|
|
if (isset($options['toprocess'])) {
|
|
$_SESSION['ldap_import']['action'] = 'process';
|
|
}
|
|
|
|
if (isset($options['change_directory'])) {
|
|
$options['ldap_filter'] = '';
|
|
}
|
|
|
|
if (!isset($_SESSION['ldap_import']['authldaps_id'])) {
|
|
$_SESSION['ldap_import']['authldaps_id'] = NOT_AVAILABLE;
|
|
}
|
|
|
|
if ((!Config::canUpdate()
|
|
&& !Entity::canUpdate())
|
|
|| (!isset($_SESSION['ldap_import']['interface'])
|
|
&& !isset($options['interface']))) {
|
|
$options['interface'] = self::SIMPLE_INTERFACE;
|
|
}
|
|
|
|
foreach ($fields as $field) {
|
|
if (isset($options[$field])) {
|
|
$_SESSION['ldap_import'][$field] = $options[$field];
|
|
}
|
|
}
|
|
if (isset($_SESSION['ldap_import']['begin_date'])
|
|
&& ($_SESSION['ldap_import']['begin_date'] == 'NULL')) {
|
|
$_SESSION['ldap_import']['begin_date'] = '';
|
|
}
|
|
if (isset($_SESSION['ldap_import']['end_date'])
|
|
&& ($_SESSION['ldap_import']['end_date'] == 'NULL')) {
|
|
$_SESSION['ldap_import']['end_date'] = '';
|
|
}
|
|
if (!isset($_SESSION['ldap_import']['criterias'])) {
|
|
$_SESSION['ldap_import']['criterias'] = [];
|
|
}
|
|
|
|
$authldap = new self();
|
|
//Filter computation
|
|
if ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE) {
|
|
$entity = new Entity();
|
|
|
|
if ($entity->getFromDB($_SESSION['ldap_import']['entities_id'])
|
|
&& ($entity->getField('authldaps_id') > 0)) {
|
|
|
|
$authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
|
|
$_SESSION['ldap_import']['authldaps_id'] = $entity->getField('authldaps_id');
|
|
$_SESSION['ldap_import']['basedn'] = $entity->getField('ldap_dn');
|
|
|
|
// No dn specified in entity : use standard one
|
|
if (empty($_SESSION['ldap_import']['basedn'])) {
|
|
$_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
|
|
}
|
|
|
|
if ($entity->getField('entity_ldapfilter') != NOT_AVAILABLE) {
|
|
$_SESSION['ldap_import']['entity_filter']
|
|
= $entity->getField('entity_ldapfilter');
|
|
}
|
|
|
|
} else {
|
|
if ($_SESSION['ldap_import']['authldaps_id'] == NOT_AVAILABLE
|
|
|| !$_SESSION['ldap_import']['authldaps_id']) {
|
|
$_SESSION['ldap_import']['authldaps_id'] = self::getDefault();
|
|
}
|
|
|
|
if ($_SESSION['ldap_import']['authldaps_id'] > 0) {
|
|
$authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
|
|
$_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
|
|
}
|
|
}
|
|
|
|
if ($_SESSION['ldap_import']['authldaps_id'] > 0) {
|
|
$_SESSION['ldap_import']['ldap_filter'] = self::buildLdapFilter($authldap);
|
|
}
|
|
|
|
} else {
|
|
if ($_SESSION['ldap_import']['authldaps_id'] == NOT_AVAILABLE
|
|
|| !$_SESSION['ldap_import']['authldaps_id']) {
|
|
|
|
$_SESSION['ldap_import']['authldaps_id'] = self::getDefault();
|
|
|
|
if ($_SESSION['ldap_import']['authldaps_id'] > 0) {
|
|
$authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
|
|
$_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
|
|
}
|
|
}
|
|
if (!isset($_SESSION['ldap_import']['ldap_filter'])
|
|
|| $_SESSION['ldap_import']['ldap_filter'] == '') {
|
|
|
|
$authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
|
|
$_SESSION['ldap_import']['basedn'] = $authldap->getField('basedn');
|
|
$_SESSION['ldap_import']['ldap_filter'] = self::buildLdapFilter($authldap);
|
|
}
|
|
}
|
|
} else { // Unset all values in session
|
|
unset($_SESSION['ldap_import']);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Show import user form
|
|
*
|
|
* @param AuthLDAP $authldap AuthLDAP object
|
|
*
|
|
* @return void
|
|
*/
|
|
static function showUserImportForm(AuthLDAP $authldap) {
|
|
|
|
//Get data related to entity (directory and ldap filter)
|
|
$authldap->getFromDB($_SESSION['ldap_import']['authldaps_id']);
|
|
echo "<div class='center'>";
|
|
|
|
echo "<form method='post' action='".$_SERVER['PHP_SELF']."'>";
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
|
|
echo "<tr><th colspan='4' class='middle'><div class='relative'>";
|
|
echo "<span>" .($_SESSION['ldap_import']['mode']?__('Synchronizing already imported users')
|
|
:__('Import new users'));
|
|
|
|
// Expert interface allow user to override configuration.
|
|
// If not coming from the ticket form, then give expert/simple link
|
|
if ((Config::canUpdate()
|
|
|| Entity::canUpdate())
|
|
&& (!isset($_SESSION['ldap_import']['no_expert_mode'])
|
|
|| $_SESSION['ldap_import']['no_expert_mode'] != 1)) {
|
|
|
|
echo "</span> <span class='floatright'><a href='".$_SERVER['PHP_SELF']."?action=".
|
|
$_SESSION['ldap_import']['action']."&mode=".$_SESSION['ldap_import']['mode'];
|
|
|
|
if ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE) {
|
|
echo "&interface=".self::EXPERT_INTERFACE."'>".__('Expert mode')."</a>";
|
|
} else {
|
|
echo "&interface=".self::SIMPLE_INTERFACE."'>".__('Simple mode')."</a>";
|
|
}
|
|
} else {
|
|
$_SESSION['ldap_import']['interface'] = self::SIMPLE_INTERFACE;
|
|
}
|
|
echo "</span></div>";
|
|
echo "</th></tr>";
|
|
|
|
switch ($_SESSION['ldap_import']['interface']) {
|
|
case self::EXPERT_INTERFACE :
|
|
//If more than one directory configured
|
|
//Display dropdown ldap servers
|
|
if (($_SESSION['ldap_import']['authldaps_id'] != NOT_AVAILABLE)
|
|
&& ($_SESSION['ldap_import']['authldaps_id'] > 0)) {
|
|
|
|
if (self::getNumberOfServers() > 1) {
|
|
$rand = mt_rand();
|
|
echo "<tr class='tab_bg_2'><td><label for='dropdown_authldaps_id$rand'>".__('LDAP directory choice')."</label></td>";
|
|
echo "<td colspan='3'>";
|
|
self::dropdown(['name' => 'authldaps_id',
|
|
'value' => $_SESSION['ldap_import']['authldaps_id'],
|
|
'condition' => ['is_active' => 1],
|
|
'display_emptychoice' => false,
|
|
'rand' => $rand]);
|
|
echo " <input class='submit' type='submit' name='change_directory'
|
|
value=\""._sx('button', 'Change')."\">";
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
echo "<tr class='tab_bg_2'><td><label for='basedn'>".__('BaseDN')."</label></td><td colspan='3'>";
|
|
echo "<input type='text' id='basedn' name='basedn' value=\"".$_SESSION['ldap_import']['basedn'].
|
|
"\" size='90' ".(!$_SESSION['ldap_import']['basedn']?"disabled":"").">";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td><label for='ldap_filter'>".__('Search filter for users')."</label></td><td colspan='3'>";
|
|
echo "<input type='text' id='ldap_filter' name='ldap_filter' value=\"".
|
|
$_SESSION['ldap_import']['ldap_filter']."\" size='90'>";
|
|
echo "</td></tr>";
|
|
}
|
|
break;
|
|
|
|
//case self::SIMPLE_INTERFACE :
|
|
default :
|
|
if (self::getNumberOfServers() > 1) {
|
|
$rand = mt_rand();
|
|
echo "<tr class='tab_bg_2'><td><label for='dropdown_authldaps_id$rand'>".__('LDAP directory choice')."</label></td>";
|
|
echo "<td colspan='3'>";
|
|
self::dropdown(['name' => 'authldaps_id',
|
|
'value' => $_SESSION['ldap_import']['authldaps_id'],
|
|
'condition' => ['is_active' => 1],
|
|
'display_emptychoice' => false,
|
|
'rand' => $rand]);
|
|
echo " <input class='submit' type='submit' name='change_directory'
|
|
value=\""._sx('button', 'Change')."\">";
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
//If multi-entity mode and more than one entity visible
|
|
//else no need to select entity
|
|
if (Session::isMultiEntitiesMode()
|
|
&& (count($_SESSION['glpiactiveentities']) > 1)) {
|
|
echo "<tr class='tab_bg_2'><td>".__('Select the desired entity')."</td>".
|
|
"<td colspan='3'>";
|
|
Entity::dropdown(['value' => $_SESSION['ldap_import']['entities_id'],
|
|
'entity' => $_SESSION['glpiactiveentities'],
|
|
'on_change' => 'this.form.submit()']);
|
|
echo "</td></tr>";
|
|
} else {
|
|
//Only one entity is active, store it
|
|
echo "<tr><td><input type='hidden' name='entities_id' value='".
|
|
$_SESSION['glpiactive_entity']."'></td></tr>";
|
|
}
|
|
|
|
if ((isset($_SESSION['ldap_import']['begin_date'])
|
|
&& !empty($_SESSION['ldap_import']['begin_date']))
|
|
|| (isset($_SESSION['ldap_import']['end_date'])
|
|
&& !empty($_SESSION['ldap_import']['end_date']))) {
|
|
$enabled = 1;
|
|
} else {
|
|
$enabled = 0;
|
|
}
|
|
Dropdown::showAdvanceDateRestrictionSwitch($enabled);
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
|
|
if (($_SESSION['ldap_import']['authldaps_id'] != NOT_AVAILABLE)
|
|
&& ($_SESSION['ldap_import']['authldaps_id'] > 0)) {
|
|
|
|
$field_counter = 0;
|
|
$fields = ['login_field' => __('Login'),
|
|
'sync_field' => __('Synchronization field') . ' (' . $authldap->fields['sync_field'] . ')',
|
|
'email1_field' => _n('Email', 'Emails', 1),
|
|
'email2_field' => sprintf(__('%1$s %2$s'),
|
|
_n('Email', 'Emails', 1), '2'),
|
|
'email3_field' => sprintf(__('%1$s %2$s'),
|
|
_n('Email', 'Emails', 1), '3'),
|
|
'email4_field' => sprintf(__('%1$s %2$s'),
|
|
_n('Email', 'Emails', 1), '4'),
|
|
'realname_field' => __('Surname'),
|
|
'firstname_field' => __('First name'),
|
|
'phone_field' => _x('ldap', 'Phone'),
|
|
'phone2_field' => __('Phone 2'),
|
|
'mobile_field' => __('Mobile phone'),
|
|
'title_field' => _x('person', 'Title'),
|
|
'category_field' => __('Category'),
|
|
'picture_field' => __('Picture')];
|
|
$available_fields = [];
|
|
foreach ($fields as $field => $label) {
|
|
if (isset($authldap->fields[$field]) && ($authldap->fields[$field] != '')) {
|
|
$available_fields[$field] = $label;
|
|
}
|
|
}
|
|
echo "<tr><th colspan='4'>" . __('Search criteria for users') . "</th></tr>";
|
|
foreach ($available_fields as $field => $label) {
|
|
if ($field_counter == 0) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
}
|
|
echo "<td><label for='criterias$field'>$label</label></td><td>";
|
|
$field_counter++;
|
|
$field_value = '';
|
|
if (isset($_SESSION['ldap_import']['criterias'][$field])) {
|
|
$field_value = Html::entities_deep(Toolbox::unclean_cross_side_scripting_deep(Toolbox::stripslashes_deep($_SESSION['ldap_import']['criterias'][$field])));
|
|
}
|
|
echo "<input type='text' id='criterias$field' name='criterias[$field]' value='$field_value'>";
|
|
echo "</td>";
|
|
if ($field_counter == 2) {
|
|
echo "</tr>";
|
|
$field_counter = 0;
|
|
}
|
|
}
|
|
if ($field_counter > 0) {
|
|
while ($field_counter < 2) {
|
|
echo "<td colspan='2'></td>";
|
|
$field_counter++;
|
|
}
|
|
$field_counter = 0;
|
|
echo "</tr>";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (($_SESSION['ldap_import']['authldaps_id'] != NOT_AVAILABLE)
|
|
&& ($_SESSION['ldap_import']['authldaps_id'] > 0)) {
|
|
|
|
if ($_SESSION['ldap_import']['authldaps_id']) {
|
|
echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
|
|
echo "<input class='submit' type='submit' name='search' value=\"".
|
|
_sx('button', 'Search')."\">";
|
|
echo "</td></tr>";
|
|
} else {
|
|
echo "<tr class='tab_bg_2'><".
|
|
"td colspan='4' class='center'>".__('No directory selected')."</td></tr>";
|
|
}
|
|
|
|
} else {
|
|
echo "<tr class='tab_bg_2'><td colspan='4' class='center'>".
|
|
__('No directory associated to entity: impossible search')."</td></tr>";
|
|
}
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
/**
|
|
* Get number of servers
|
|
*
|
|
* @var DBmysql $DB
|
|
*
|
|
* @return integer
|
|
*/
|
|
static function getNumberOfServers() {
|
|
return countElementsInTable('glpi_authldaps', ['is_active' => 1]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Build LDAP filter
|
|
*
|
|
* @param AuthLDAP $authldap AuthLDAP object
|
|
*
|
|
* @return string
|
|
*/
|
|
static function buildLdapFilter(AuthLDAP $authldap) {
|
|
//Build search filter
|
|
$counter = 0;
|
|
$filter = '';
|
|
|
|
if (!empty($_SESSION['ldap_import']['criterias'])
|
|
&& ($_SESSION['ldap_import']['interface'] == self::SIMPLE_INTERFACE)) {
|
|
|
|
foreach ($_SESSION['ldap_import']['criterias'] as $criteria => $value) {
|
|
if ($value != '') {
|
|
$begin = 0;
|
|
$end = 0;
|
|
if (($length = strlen($value)) > 0) {
|
|
if ($value[0] == '^') {
|
|
$begin = 1;
|
|
}
|
|
if ($value[$length-1] == '$') {
|
|
$end = 1;
|
|
}
|
|
}
|
|
if ($begin || $end) {
|
|
// no Toolbox::substr, to be consistent with strlen result
|
|
$value = substr($value, $begin, $length-$end-$begin);
|
|
}
|
|
$counter++;
|
|
$filter .= '('.$authldap->fields[$criteria].'='.($begin?'':'*').$value.($end?'':'*').')';
|
|
}
|
|
}
|
|
} else {
|
|
$filter = "(".$authldap->getField("login_field")."=*)";
|
|
}
|
|
|
|
//If time restriction
|
|
$begin_date = (isset($_SESSION['ldap_import']['begin_date'])
|
|
&& !empty($_SESSION['ldap_import']['begin_date'])
|
|
? $_SESSION['ldap_import']['begin_date'] : null);
|
|
$end_date = (isset($_SESSION['ldap_import']['end_date'])
|
|
&& !empty($_SESSION['ldap_import']['end_date'])
|
|
? $_SESSION['ldap_import']['end_date'] : null);
|
|
$filter .= self::addTimestampRestrictions($begin_date, $end_date);
|
|
$ldap_condition = $authldap->getField('condition');
|
|
//Add entity filter and filter filled in directory's configuration form
|
|
return "(&".(isset($_SESSION['ldap_import']['entity_filter'])
|
|
?$_SESSION['ldap_import']['entity_filter']
|
|
:'')." $filter $ldap_condition)";
|
|
}
|
|
|
|
|
|
/**
|
|
* Add timestamp restriction
|
|
*
|
|
* @param string $begin_date datetime begin date to search (NULL if not take into account)
|
|
* @param string $end_date datetime end date to search (NULL if not take into account)
|
|
*
|
|
* @return string
|
|
*/
|
|
static function addTimestampRestrictions($begin_date, $end_date) {
|
|
|
|
$condition = '';
|
|
//If begin date
|
|
if (!empty($begin_date)) {
|
|
$stampvalue = self::date2ldapTimeStamp($begin_date);
|
|
$condition .= "(modifyTimestamp>=".$stampvalue.")";
|
|
}
|
|
//If end date
|
|
if (!empty($end_date)) {
|
|
$stampvalue = self::date2ldapTimeStamp($end_date);
|
|
$condition .= "(modifyTimestamp<=".$stampvalue.")";
|
|
}
|
|
return $condition;
|
|
}
|
|
|
|
|
|
/**
|
|
* Search user
|
|
*
|
|
* @param resource $authldap AuthLDAP object
|
|
*
|
|
* @return void
|
|
*/
|
|
static function searchUser(AuthLDAP $authldap) {
|
|
|
|
if (self::connectToServer($authldap->getField('host'), $authldap->getField('port'),
|
|
$authldap->getField('rootdn'),
|
|
Toolbox::sodiumDecrypt($authldap->getField('rootdn_passwd')),
|
|
$authldap->getField('use_tls'),
|
|
$authldap->getField('deref_option'))) {
|
|
self::showLdapUsers();
|
|
|
|
} else {
|
|
echo "<div class='center b firstbloc'>".__('Unable to connect to the LDAP directory');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get default ldap
|
|
*
|
|
* @var DBmysql $DB DB instance
|
|
*
|
|
* @return integer
|
|
*/
|
|
static function getDefault() {
|
|
global $DB;
|
|
|
|
foreach ($DB->request('glpi_authldaps', ['is_default' => 1, 'is_active' => 1]) as $data) {
|
|
return $data['id'];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function post_updateItem($history = 1) {
|
|
global $DB;
|
|
|
|
if (in_array('is_default', $this->updates) && $this->input["is_default"]==1) {
|
|
$DB->update(
|
|
$this->getTable(),
|
|
['is_default' => 0],
|
|
['id' => ['<>', $this->input['id']]]
|
|
);
|
|
}
|
|
}
|
|
|
|
function post_addItem() {
|
|
global $DB;
|
|
|
|
if (isset($this->fields['is_default']) && $this->fields["is_default"]==1) {
|
|
$DB->update(
|
|
$this->getTable(),
|
|
['is_default' => 0],
|
|
['id' => ['<>', $this->fields['id']]]
|
|
);
|
|
}
|
|
}
|
|
|
|
function prepareInputForAdd($input) {
|
|
|
|
//If it's the first ldap directory then set it as the default directory
|
|
if (!self::getNumberOfServers()) {
|
|
$input['is_default'] = 1;
|
|
}
|
|
|
|
if (isset($input["rootdn_passwd"]) && !empty($input["rootdn_passwd"])) {
|
|
$input["rootdn_passwd"] = Toolbox::sodiumEncrypt(stripslashes($input["rootdn_passwd"]));
|
|
}
|
|
|
|
return $input;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get LDAP deleted user action options.
|
|
*
|
|
* @return array
|
|
*/
|
|
static function getLdapDeletedUserActionOptions() {
|
|
|
|
return [
|
|
self::DELETED_USER_PRESERVE => __('Preserve'),
|
|
self::DELETED_USER_DELETE => __('Put in trashbin'),
|
|
self::DELETED_USER_WITHDRAWDYNINFO => __('Withdraw dynamic authorizations and groups'),
|
|
self::DELETED_USER_DISABLE => __('Disable'),
|
|
self::DELETED_USER_DISABLEANDWITHDRAWDYNINFO => __('Disable').' + '.__('Withdraw dynamic authorizations and groups'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Builds deleted actions dropdown
|
|
*
|
|
* @param integer $value (default 0)
|
|
*
|
|
* @return string
|
|
*/
|
|
static function dropdownUserDeletedActions($value = 0) {
|
|
|
|
$options = self::getLdapDeletedUserActionOptions();
|
|
asort($options);
|
|
return Dropdown::showFromArray('user_deleted_ldap', $options, ['value' => $value]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Return all the ldap servers where email field is configured
|
|
*
|
|
* @return array of LDAP server's ID
|
|
*/
|
|
static function getServersWithImportByEmailActive() {
|
|
global $DB;
|
|
|
|
$ldaps = [];
|
|
// Always get default first
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => ['id'],
|
|
'FROM' => 'glpi_authldaps',
|
|
'WHERE' => [
|
|
'is_active' => 1,
|
|
'OR' => [
|
|
'email1_field' => ['<>', ''],
|
|
'email2_field' => ['<>', ''],
|
|
'email3_field' => ['<>', ''],
|
|
'email4_field' => ['<>', '']
|
|
]
|
|
],
|
|
'ORDER' => ['is_default DESC']
|
|
]);
|
|
while ($data = $iterator->next()) {
|
|
$ldaps[] = $data['id'];
|
|
}
|
|
return $ldaps;
|
|
}
|
|
|
|
|
|
/**
|
|
* Show date restriction form
|
|
*
|
|
* @param array $options Options
|
|
*
|
|
* @return void
|
|
*/
|
|
static function showDateRestrictionForm($options = []) {
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr class='tab_bg_2'>";
|
|
|
|
$enabled = (isset($options['enabled'])?$options['enabled']:false);
|
|
if (!$enabled) {
|
|
echo "<td colspan='4' class='center'>";
|
|
echo "<a href='#' onClick='activateRestriction()'>".__('Enable filtering by date')."</a>";
|
|
echo "</td></tr>";
|
|
}
|
|
if ($enabled) {
|
|
echo "<td>".__('View updated users')."</td>";
|
|
echo "<td>".__('from')."</td>";
|
|
echo "<td>";
|
|
$begin_date = (isset($_SESSION['ldap_import']['begin_date'])
|
|
?$_SESSION['ldap_import']['begin_date'] :'');
|
|
Html::showDateTimeField("begin_date", ['value' => $begin_date]);
|
|
echo "</td>";
|
|
echo "<td>".__('to')."</td>";
|
|
echo "<td>";
|
|
$end_date = (isset($_SESSION['ldap_import']['end_date'])
|
|
?$_SESSION['ldap_import']['end_date']
|
|
:date('Y-m-d H:i:s', time()-DAY_TIMESTAMP));
|
|
Html::showDateTimeField("end_date", ['value' => $end_date]);
|
|
echo "</td></tr>";
|
|
echo "<tr class='tab_bg_2'><td colspan='4' class='center'>";
|
|
echo "<a href='#' onClick='deactivateRestriction()'>".__('Disable filtering by date')."</a>";
|
|
echo "</td></tr>";
|
|
}
|
|
echo "</table>";
|
|
}
|
|
|
|
function cleanDBonPurge() {
|
|
Rule::cleanForItemCriteria($this, 'LDAP_SERVER');
|
|
}
|
|
|
|
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
|
|
|
|
if (!$withtemplate
|
|
&& $item->can($item->getField('id'), READ)) {
|
|
$ong = [];
|
|
$ong[1] = _sx('button', 'Test'); // test connexion
|
|
$ong[2] = User::getTypeName(Session::getPluralNumber());
|
|
$ong[3] = Group::getTypeName(Session::getPluralNumber());
|
|
// TODO clean fields entity_XXX if not used
|
|
// $ong[4] = Entity::getTypeName(1); // params for entity config
|
|
$ong[5] = __('Advanced information'); // params for entity advanced config
|
|
$ong[6] = _n('Replicate', 'Replicates', Session::getPluralNumber());
|
|
|
|
return $ong;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Choose wich form to show
|
|
*
|
|
* @param CommonGLPI $item Item instance
|
|
* @param integer $tabnum Tab number
|
|
* @param integer $withtemplate Unused
|
|
*
|
|
* @return boolean (TRUE)
|
|
*/
|
|
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
|
|
|
|
switch ($tabnum) {
|
|
case 1 :
|
|
$item->showFormTestLDAP();
|
|
break;
|
|
|
|
case 2 :
|
|
$item->showFormUserConfig();
|
|
break;
|
|
|
|
case 3 :
|
|
$item->showFormGroupsConfig();
|
|
break;
|
|
|
|
case 4 :
|
|
$item->showFormEntityConfig();
|
|
break;
|
|
|
|
case 5 :
|
|
$item->showFormAdvancedConfig();
|
|
break;
|
|
|
|
case 6 :
|
|
$item->showFormReplicatesConfig();
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get ldap query results and clean them at the same time
|
|
*
|
|
* @param resource $link link to the directory connection
|
|
* @param array $result the query results
|
|
*
|
|
* @return array which contains ldap query results
|
|
*/
|
|
static function get_entries_clean($link, $result) {
|
|
return ldap_get_entries($link, $result);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all replicate servers for a master one
|
|
*
|
|
* @param integer $master_id master ldap server ID
|
|
*
|
|
* @return array of the replicate servers
|
|
*/
|
|
static function getAllReplicateForAMaster($master_id) {
|
|
global $DB;
|
|
|
|
$replicates = [];
|
|
$criteria = ['FIELDS' => ['id', 'host', 'port'],
|
|
'FROM' => 'glpi_authldapreplicates',
|
|
'WHERE' => ['authldaps_id' => $master_id]
|
|
];
|
|
foreach ($DB->request($criteria) as $replicate) {
|
|
$replicates[] = ["id" => $replicate["id"],
|
|
"host" => $replicate["host"],
|
|
"port" => $replicate["port"]
|
|
];
|
|
}
|
|
return $replicates;
|
|
}
|
|
|
|
/**
|
|
* Check if ldap results can be paged or not
|
|
* This functionality is available for PHP 5.4 and higher
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @param object $config_ldap LDAP configuration
|
|
* @param boolean $check_config_value Whether to check config values
|
|
*
|
|
* @return boolean true if maxPageSize can be used, false otherwise
|
|
*/
|
|
static function isLdapPageSizeAvailable($config_ldap, $check_config_value = true) {
|
|
return (extension_loaded('ldap') && (!$check_config_value
|
|
|| ($check_config_value && $config_ldap->fields['can_support_pagesize'])));
|
|
}
|
|
|
|
/**
|
|
* Does LDAP user already exists in the database?
|
|
*
|
|
* @param string $name User login/name
|
|
* @param string $sync Sync field
|
|
*
|
|
* @return false|User
|
|
*/
|
|
public function getLdapExistingUser($name, $authldaps_id, $sync = null) {
|
|
global $DB;
|
|
$user = new User();
|
|
|
|
if ($sync !== null && $user->getFromDBbySyncField($sync)) {
|
|
return $user;
|
|
}
|
|
|
|
if ($user->getFromDBbyNameAndAuth($DB->escape($name), Auth::LDAP, $authldaps_id)) {
|
|
return $user;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Is synchronisation field used for current server
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isSyncFieldUsed() {
|
|
$count = countElementsInTable(
|
|
'glpi_users',
|
|
[
|
|
'auths_id' => $this->getID(),
|
|
'NOT' => ['sync_field' => null]
|
|
]
|
|
);
|
|
return $count > 0;
|
|
}
|
|
|
|
/**
|
|
* Get a LDAP field value
|
|
*
|
|
* @param array $infos LDAP entry infos
|
|
* @param string $field Field name to retrieve
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getFieldValue($infos, $field) {
|
|
$value = null;
|
|
if (is_array($infos[$field])) {
|
|
$value = $infos[$field][0];
|
|
} else {
|
|
$value = $infos[$field];
|
|
}
|
|
if ($field != 'objectguid') {
|
|
return $value;
|
|
}
|
|
|
|
//handle special objectguid from AD directories
|
|
try {
|
|
//prevent double encoding
|
|
if (!self::isValidGuid($value)) {
|
|
$value = self::guidToString($value);
|
|
if (!self::isValidGuid($value)) {
|
|
throw new \RuntimeException('Not an objectguid!');
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
//well... this is not an objectguid apparently
|
|
$value = $infos[$field];
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Converts a string representation of an objectguid to hexadecimal
|
|
* Used to build filters
|
|
*
|
|
* @param string $guid_str String representation
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function guidToHex($guid_str) {
|
|
$str_g = explode('-', $guid_str);
|
|
|
|
$str_g[0] = strrev($str_g[0]);
|
|
$str_g[1] = strrev($str_g[1]);
|
|
$str_g[2] = strrev($str_g[2]);
|
|
|
|
$guid_hex = '\\';
|
|
$strrev = 0;
|
|
foreach ($str_g as $str) {
|
|
for ($i = 0; $i < strlen($str)+2; $i++) {
|
|
if ($strrev < 3) {
|
|
$guid_hex .= strrev(substr($str, 0, 2)).'\\';
|
|
} else {
|
|
$guid_hex .= substr($str, 0, 2).'\\';
|
|
}
|
|
$str = substr($str, 2);
|
|
}
|
|
if ($strrev < 3) {
|
|
$guid_hex .= strrev($str);
|
|
} else {
|
|
$guid_hex .= $str;
|
|
}
|
|
$strrev++;
|
|
}
|
|
return $guid_hex;
|
|
}
|
|
|
|
/**
|
|
* Converts binary objectguid to string representation
|
|
*
|
|
* @param mixed $guid_bin Binary objectguid from AD
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function guidToString($guid_bin) {
|
|
$guid_hex = unpack("H*hex", $guid_bin);
|
|
$hex = $guid_hex["hex"];
|
|
|
|
$hex1 = substr($hex, -26, 2) . substr($hex, -28, 2) . substr($hex, -30, 2) . substr($hex, -32, 2);
|
|
$hex2 = substr($hex, -22, 2) . substr($hex, -24, 2);
|
|
$hex3 = substr($hex, -18, 2) . substr($hex, -20, 2);
|
|
$hex4 = substr($hex, -16, 4);
|
|
$hex5 = substr($hex, -12, 12);
|
|
|
|
$guid_str = $hex1 . "-" . $hex2 . "-" . $hex3 . "-" . $hex4 . "-" . $hex5;
|
|
return $guid_str;
|
|
}
|
|
|
|
/**
|
|
* Check if text representation of an objectguid is valid
|
|
*
|
|
* @param string $string Strign representation
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public static function isValidGuid($guid_str) {
|
|
return (bool) preg_match('/^([0-9a-fA-F]){8}(-([0-9a-fA-F]){4}){3}-([0-9a-fA-F]){12}$/', $guid_str);
|
|
}
|
|
|
|
/**
|
|
* Get the list of LDAP users to add/synchronize
|
|
* When importing, already existing users will be filtered
|
|
*
|
|
* @param array $values possible options:
|
|
* - authldaps_id ID of the server to use
|
|
* - mode user to synchronise or add?
|
|
* - ldap_filter ldap filter to use
|
|
* - basedn force basedn (default authldaps_id one)
|
|
* - order display order
|
|
* - begin_date begin date to time limit
|
|
* - end_date end date to time limit
|
|
* - script true if called by an external script
|
|
* @param array $results result stats
|
|
* @param boolean $limitexceeded limit exceeded exception
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getUsers($values, &$results, &$limitexceeded) {
|
|
$users = [];
|
|
$ldap_users = self::getAllUsers($values, $results, $limitexceeded);
|
|
|
|
$config_ldap = new AuthLDAP();
|
|
$config_ldap->getFromDB($values['authldaps_id']);
|
|
|
|
if (!is_array($ldap_users) || count($ldap_users) == 0) {
|
|
return $users;
|
|
}
|
|
|
|
foreach ($ldap_users as $userinfos) {
|
|
$user_to_add = [];
|
|
$user = new User();
|
|
|
|
$user_sync_field = null;
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
$sync_field = $config_ldap->fields['sync_field'];
|
|
if (isset($userinfos[$sync_field])) {
|
|
$user_sync_field = self::getFieldValue($userinfos, $sync_field);
|
|
}
|
|
}
|
|
|
|
$user = $config_ldap->getLdapExistingUser($userinfos['user'], $values['authldaps_id'],
|
|
$user_sync_field);
|
|
if (isset($_SESSION['ldap_import']) && !$_SESSION['ldap_import']['mode'] && $user) {
|
|
continue;
|
|
}
|
|
$user_to_add['link'] = $userinfos["user"];
|
|
if (isset($userinfos['id']) && User::canView()) {
|
|
$user_to_add['id'] = $userinfos['id'];
|
|
$user_to_add['name'] = $user->fields['name'];
|
|
$user_to_add['link'] = Toolbox::getItemTypeFormURL('User').'?id='.$userinfos['id'];
|
|
}
|
|
|
|
$user_to_add['stamp'] = (isset($userinfos["timestamp"])) ? $userinfos["timestamp"] : '';
|
|
$user_to_add['date_sync'] = (isset($userinfos["date_sync"])) ? $userinfos["date_sync"] : '';
|
|
|
|
$user_to_add['uid'] = $userinfos['user'];
|
|
if ($config_ldap->isSyncFieldEnabled()) {
|
|
if (isset($userinfos[$sync_field])) {
|
|
$user_to_add['uid'] = self::getFieldValue($userinfos, $sync_field);
|
|
}
|
|
|
|
$field_for_sync = $config_ldap->getLdapIdentifierToUse();
|
|
if (isset($userinfos[$field_for_sync])) {
|
|
$user_to_add['sync_field'] = $userinfos[$field_for_sync];
|
|
}
|
|
}
|
|
|
|
$users[] = $user_to_add;
|
|
}
|
|
|
|
return $users;
|
|
}
|
|
}
|