Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,7 @@
$ignoreErrors[] = [
'message' => '#^Access to an undefined property object\\:\\:\\$fields\\.$#',
'identifier' => 'property.notFound',
'count' => 16,
'count' => 11,
'path' => __DIR__ . '/src/AuthLDAP.php',
];
$ignoreErrors[] = [
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The present file will list all changes made to the project; according to the
### Removed
- `itemtype` criteria for Ticket and Change rules. This has been non-operational since 0.85 (over 11 years ago).
- POP protocol support for mails receivers and mail authentication servers. Existing mails receivers and authentication servers using it are disabled during the update.
- "Used paged results" option for LDAP authentication. If an LDAP server is not able to handle paged results, it will automatically be handled now.

### API changes

Expand All @@ -38,6 +39,7 @@ The present file will list all changes made to the project; according to the
- `Html::getConfirmationOnActionScript()`. Use the `data-glpi-confirm="<message>"` attribute instead.
- `Html::link()`.
- `confirmaction` option of `Html::submit()`. Confirmation is now handled through the `data-glpi-confirm` attribute, so no additional action can be run on confirmation.
- `AuthLDAP::isLdapPageSizeAvailable()`. The LDAP page size is always available now (with an automatic fallback at least).

## [12.0.2] unreleased

Expand Down
53 changes: 53 additions & 0 deletions install/migrations/update_12.0.x_to_13.0.0/authldap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2026 Teclib' and contributors.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

/**
* @var Migration $migration
* @var DBmysql $DB
*/

// can_support_pagesize has not been needed since GLPI stopped supporting PHP versions older than 5.4
$migration->dropField('glpi_authldaps', 'can_support_pagesize');

// pagesize is always available now (at least with an automatic fallback), so we can set it to 1000 for all existing LDAP authentication servers where it is set to 0 or null
$iterator = $DB->request([
'SELECT' => ['id'],
'FROM' => 'glpi_authldaps',
'WHERE' => [
'pagesize' => ['IN', [0, null]],
],
]);
foreach ($iterator as $data) {
$DB->update('glpi_authldaps', ['pagesize' => 1000], ['id' => $data['id']]);
}
1 change: 0 additions & 1 deletion install/mysql/glpi-empty.sql
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ CREATE TABLE `glpi_authldaps` (
`responsible_field` varchar(255) DEFAULT NULL,
`pagesize` int NOT NULL DEFAULT '0',
`ldap_maxlimit` int NOT NULL DEFAULT '0',
`can_support_pagesize` tinyint NOT NULL DEFAULT '0',
`picture_field` varchar(255) DEFAULT NULL,
`begin_date_field` varchar(255) DEFAULT NULL,
`end_date_field` varchar(255) DEFAULT NULL,
Expand Down
205 changes: 76 additions & 129 deletions src/AuthLDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,7 @@ public function post_getEmpty()
$this->fields['use_bind'] = 1;
$this->fields['picture_field'] = '';
$this->fields['responsible_field'] = '';
$this->fields['can_support_pagesize'] = 0;
$this->fields['pagesize'] = 0;
$this->fields['pagesize'] = 1000;
$this->fields['ldap_maxlimit'] = 0;
$this->fields['begin_date_field'] = '';
$this->fields['end_date_field'] = '';
Expand Down Expand Up @@ -249,7 +248,6 @@ public function preconfig($type)
$this->fields['comment_field'] = 'info';
$this->fields['title_field'] = 'title';
$this->fields['use_dn'] = 1;
$this->fields['can_support_pagesize'] = 1;
$this->fields['pagesize'] = 1000;
$this->fields['picture_field'] = '';
$this->fields['responsible_field'] = 'manager';
Expand Down Expand Up @@ -279,7 +277,6 @@ public function preconfig($type)
$this->fields['comment_field'] = 'description';
$this->fields['title_field'] = 'title';
$this->fields['use_dn'] = 1;
$this->fields['can_support_pagesize'] = 1;
$this->fields['pagesize'] = 1000;
$this->fields['picture_field'] = 'jpegphoto';
$this->fields['responsible_field'] = 'manager';
Expand All @@ -295,6 +292,9 @@ public function preconfig($type)

public function prepareInputForUpdate($input)
{
if (isset($input['pagesize']) && ((int) $input['pagesize'] <= 0)) {
unset($input['pagesize']);
}
if (isset($input["rootdn_passwd"])) {
if (empty($input["rootdn_passwd"])) {
unset($input["rootdn_passwd"]);
Expand Down Expand Up @@ -489,7 +489,7 @@ public function showForm($ID, array $options = [])
'realname_field', 'registration_number_field', 'title_field',
'use_dn', 'use_tls', 'picture_field', 'responsible_field', 'begin_date_field', 'end_date_field',
'category_field', 'language_field', 'location_field',
'can_support_pagesize', 'pagesize',
'pagesize',
];
}

Expand Down Expand Up @@ -537,7 +537,6 @@ public function showFormAdvancedConfig()

TemplateRenderer::getInstance()->display('pages/setup/ldap/adv_info.html.twig', [
'item' => $this,
'page_size_available' => self::isLdapPageSizeAvailable(false, false),
'gmt_values' => Dropdown::getGMTValues(),
'params' => [
'formfooter' => false,
Expand Down Expand Up @@ -1739,60 +1738,45 @@ public static function searchForUsers(
&$ldap_users_by_dn = null
) {

// 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
$page_size = (int) ($config_ldap->fields['pagesize'] ?? 0);
if ($page_size <= 0) {
$page_size = 1000;
}

do {
if (self::isLdapPageSizeAvailable($config_ldap)) {
$controls = [
[
'oid' => LDAP_CONTROL_PAGEDRESULTS,
'iscritical' => true,
'value' => [
'size' => $config_ldap->fields['pagesize'],
'cookie' => $cookie,
],
// The paged results control is not critical: if the server does not support it (or restricts it),
// it will ignore it and return all results at once, without any page cookie.
$controls = [
[
'oid' => LDAP_CONTROL_PAGEDRESULTS,
'iscritical' => false,
'value' => [
'size' => $page_size,
'cookie' => $cookie,
],
];
$sr = @ldap_search($ds, $values['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
if (
$sr === false
|| @ldap_parse_result($ds, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls) === false // @phpstan-ignore theCodingMachineSafe.function
) {
// 32 = LDAP_NO_SUCH_OBJECT => This error can be silented as it just means that search produces no result.
if (ldap_errno($ds) !== 32) {
trigger_error(
static::buildError(
$ds,
sprintf('LDAP search with base DN `%s` and filter `%s` failed', $values['basedn'], $filter)
),
E_USER_WARNING
);
}
return false;
}
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 === false) {
// 32 = LDAP_NO_SUCH_OBJECT => This error can be silented as it just means that search produces no result.
if (ldap_errno($ds) !== 32) {
trigger_error(
static::buildError(
$ds,
sprintf('LDAP search with base DN `%s` and filter `%s` failed', $values['basedn'], $filter)
),
E_USER_WARNING
);
}
return false;
],
];
$sr = @ldap_search($ds, $values['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
if (
$sr === false
|| @ldap_parse_result($ds, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls) === false // @phpstan-ignore theCodingMachineSafe.function
) {
// 32 = LDAP_NO_SUCH_OBJECT => This error can be silented as it just means that search produces no result.
if (ldap_errno($ds) !== 32) {
trigger_error(
static::buildError(
$ds,
sprintf('LDAP search with base DN `%s` and filter `%s` failed', $values['basedn'], $filter)
),
E_USER_WARNING
);
}
return false;
}
// No page cookie in the response means that there are no more pages (or that paging is not supported)
$cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? '';

if (in_array(ldap_errno($ds), [4,11])) {
// openldap return 4 for Size limit exceeded
Expand All @@ -1806,11 +1790,10 @@ public static function searchForUsers(
}

$count += $info['count'];
//If page results are enabled and the number of results is greater than the maximum allowed
//If 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']
$config_ldap->fields['ldap_maxlimit']
&& ($count > $config_ldap->fields['ldap_maxlimit'])
) {
$limitexceeded = true;
Expand Down Expand Up @@ -2417,56 +2400,43 @@ public static function getGroupsFromLDAP(
}
$cookie = '';
$count = 0;
$page_size = (int) ($config_ldap->fields['pagesize'] ?? 0);
if ($page_size <= 0) {
$page_size = 1000;
}

do {
if (self::isLdapPageSizeAvailable($config_ldap)) {
$controls = [
[
'oid' => LDAP_CONTROL_PAGEDRESULTS,
'iscritical' => true,
'value' => [
'size' => $config_ldap->fields['pagesize'],
'cookie' => $cookie,
],
// The paged results control is not critical: if the server does not support it (or restricts it),
// it will ignore it and return all results at once, without any page cookie.
$controls = [
[
'oid' => LDAP_CONTROL_PAGEDRESULTS,
'iscritical' => false,
'value' => [
'size' => $page_size,
'cookie' => $cookie,
],
];
$sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
if (
$sr === false
|| @ldap_parse_result($ldap_connection, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls) === false // @phpstan-ignore theCodingMachineSafe.function
) {
// 32 = LDAP_NO_SUCH_OBJECT => This error can be silented as it just means that search produces no result.
if (ldap_errno($ldap_connection) !== 32) {
trigger_error(
static::buildError(
$ldap_connection,
sprintf('LDAP search with base DN `%s` and filter `%s` failed', $config_ldap->fields['basedn'], $filter)
),
E_USER_WARNING
);
}
return $groups;
}
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 === false) {
// 32 = LDAP_NO_SUCH_OBJECT => This error can be silented as it just means that search produces no result.
if (ldap_errno($ldap_connection) !== 32) {
trigger_error(
static::buildError(
$ldap_connection,
sprintf('LDAP search with base DN `%s` and filter `%s` failed', $config_ldap->fields['basedn'], $filter)
),
E_USER_WARNING
);
}
return $groups;
],
];
$sr = @ldap_search($ldap_connection, $config_ldap->fields['basedn'], $filter, $attrs, 0, -1, -1, LDAP_DEREF_NEVER, $controls);
if (
$sr === false
|| @ldap_parse_result($ldap_connection, $sr, $errcode, $matcheddn, $errmsg, $referrals, $controls) === false // @phpstan-ignore theCodingMachineSafe.function
) {
// 32 = LDAP_NO_SUCH_OBJECT => This error can be silented as it just means that search produces no result.
if (ldap_errno($ldap_connection) !== 32) {
trigger_error(
static::buildError(
$ldap_connection,
sprintf('LDAP search with base DN `%s` and filter `%s` failed', $config_ldap->fields['basedn'], $filter)
),
E_USER_WARNING
);
}
return $groups;
}
// No page cookie in the response means that there are no more pages (or that paging is not supported)
$cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? '';

if (in_array(ldap_errno($ldap_connection), [4,11])) {
// openldap return 4 for Size limit exceeded
Expand All @@ -2480,11 +2450,10 @@ public static function getGroupsFromLDAP(
}

$count += $infos['count'];
// If page results are enabled and the number of results is greater than the maximum allowed
// If 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']
$config_ldap->fields['ldap_maxlimit']
&& ($count > $config_ldap->fields['ldap_maxlimit'])
) {
$limitexceeded = true;
Expand Down Expand Up @@ -3899,8 +3868,8 @@ public function post_addItem()

public function prepareInputForAdd($input)
{
if (empty($input['can_support_pagesize'] ?? '')) {
$input['can_support_pagesize'] = 0;
if (empty($input['pagesize'] ?? '')) {
$input['pagesize'] = 1000;
}

if (!empty($input["rootdn_passwd"])) {
Expand Down Expand Up @@ -4106,28 +4075,6 @@ public static function getAllReplicateForAMaster($master_id)
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 ($check_config_value is true ? object : false) $config_ldap LDAP configuration. May only be false if $check_config_value is also false.
* @param bool $check_config_value Whether to check config values
*
* @return bool true if maxPageSize can be used, false otherwise
*/
public static function isLdapPageSizeAvailable($config_ldap, $check_config_value = true)
{
return (
extension_loaded('ldap')
&& (
!$check_config_value
|| $config_ldap->fields['can_support_pagesize']
)
);
}

/**
* Does LDAP user already exists in the database?
*
Expand Down
Loading
Loading