From 202d61dd4e60f42c8f243366aa22621b4d7b9ff1 Mon Sep 17 00:00:00 2001 From: Markus Frosch Date: Tue, 5 Apr 2016 15:02:10 +0200 Subject: [PATCH] lib/LDAP: Add support for LDAP search scope Configurable on the LdapQuery, handled by LdapConnection::ldapSearch refs #11485 --- .../Icinga/Protocol/Ldap/LdapConnection.php | 23 ++++++- library/Icinga/Protocol/Ldap/LdapQuery.php | 68 +++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/library/Icinga/Protocol/Ldap/LdapConnection.php b/library/Icinga/Protocol/Ldap/LdapConnection.php index 0729addfc..2d9ee358a 100644 --- a/library/Icinga/Protocol/Ldap/LdapConnection.php +++ b/library/Icinga/Protocol/Ldap/LdapConnection.php @@ -4,6 +4,7 @@ namespace Icinga\Protocol\Ldap; use Exception; +use LogicException; use ArrayIterator; use Icinga\Application\Config; use Icinga\Application\Logger; @@ -1179,6 +1180,8 @@ class LdapConnection implements Selectable, Inspectable * @param int $deref * * @return resource|bool A search result identifier or false on error + * + * @throws LogicException If the LDAP query search scope is unsupported */ public function ldapSearch( LdapQuery $query, @@ -1190,6 +1193,7 @@ class LdapConnection implements Selectable, Inspectable ) { $queryString = (string) $query; $baseDn = $query->getBase() ?: $this->getDn(); + $scope = $query->getScope(); if (Logger::getInstance()->getLevel() === Logger::DEBUG) { // We're checking the level by ourself to avoid rendering the ldapsearch commandline for nothing @@ -1213,11 +1217,12 @@ class LdapConnection implements Selectable, Inspectable } Logger::debug("Issueing LDAP search. Use '%s' to reproduce.", sprintf( - 'ldapsearch -P 3%s -H "%s"%s -b "%s" -s "sub" -z %u -l %u -a "%s"%s%s%s', + 'ldapsearch -P 3%s -H "%s"%s -b "%s" -s "%s" -z %u -l %u -a "%s"%s%s%s', $starttlsParam, $ldapUrl, $bindParams, $baseDn, + $scope, $sizelimit, $timelimit, $derefName, @@ -1227,7 +1232,21 @@ class LdapConnection implements Selectable, Inspectable )); } - return @ldap_search( + switch($scope) { + case LdapQuery::SCOPE_SUB: + $function = 'ldap_search'; + break; + case LdapQuery::SCOPE_ONE: + $function = 'ldap_list'; + break; + case LdapQuery::SCOPE_BASE: + $function = 'ldap_read'; + break; + default: + throw new LogicException('LDAP scope %s not supported by ldapSearch', $scope); + } + + return @$function( $this->getConnection(), $baseDn, $queryString, diff --git a/library/Icinga/Protocol/Ldap/LdapQuery.php b/library/Icinga/Protocol/Ldap/LdapQuery.php index 1184765ba..7f31d32a0 100644 --- a/library/Icinga/Protocol/Ldap/LdapQuery.php +++ b/library/Icinga/Protocol/Ldap/LdapQuery.php @@ -3,6 +3,7 @@ namespace Icinga\Protocol\Ldap; +use LogicException; use Icinga\Data\SimpleQuery; /** @@ -38,6 +39,39 @@ class LdapQuery extends SimpleQuery */ protected $nativeFilter; + /** + * Only fetch the entry at the base of the search + */ + const SCOPE_BASE = 'base'; + + /** + * Fetch entries one below the base DN + */ + const SCOPE_ONE = 'one'; + + /** + * Fetch all entries below the base DN + */ + const SCOPE_SUB = 'sub'; + + /** + * All available scopes + * + * @var array + */ + public static $scopes = array( + LdapQuery::SCOPE_BASE, + LdapQuery::SCOPE_ONE, + LdapQuery::SCOPE_SUB + ); + + /** + * LDAP search scope (default: SCOPE_SUB) + * + * @var string + */ + protected $scope = LdapQuery::SCOPE_SUB; + /** * Initialize this query */ @@ -223,4 +257,38 @@ class LdapQuery extends SimpleQuery { return $this->renderFilter(); } + + /** + * Get LDAP search scope + * + * @return string + */ + public function getScope() + { + return $this->scope; + } + + /** + * Set LDAP search scope + * + * Valid: sub one base (Default: sub) + * + * @param string $scope + * + * @return LdapQuery + * + * @throws LogicException If scope value is invalid + */ + public function setScope($scope) + { + if (! in_array($scope, static::$scopes)) { + throw new LogicException( + 'Can\'t set scope %d, it is is invalid. Use one of %s or LdapQuery\'s constants.', + $scope, implode(', ', static::$scopes) + ); + } + $this->scope = $scope; + return $this; + } + }