LdapQuery: Add support for Icinga\Data\Filter

refs #10370
This commit is contained in:
Johannes Meyer 2015-11-09 15:59:48 +01:00
parent 9b826e6e5f
commit 4341eef4b1
2 changed files with 94 additions and 75 deletions

View File

@ -7,13 +7,14 @@ use Exception;
use ArrayIterator;
use Icinga\Application\Config;
use Icinga\Application\Logger;
use Icinga\Application\Platform;
use Icinga\Data\ConfigObject;
use Icinga\Data\Inspectable;
use Icinga\Data\Inspection;
use Icinga\Data\Selectable;
use Icinga\Data\Sortable;
use Icinga\Exception\InspectionException;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterChain;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Exception\ProgrammingError;
use Icinga\Protocol\Ldap\LdapException;
@ -1184,6 +1185,93 @@ class LdapConnection implements Selectable, Inspectable
return $dir;
}
/**
* Render and return a valid LDAP filter representation of the given filter
*
* @param Filter $filter
* @param int $level
*
* @return string
*/
public function renderFilter(Filter $filter, $level = 0)
{
if ($filter->isExpression()) {
/** @var $filter FilterExpression */
return $this->renderFilterExpression($filter);
}
/** @var $filter FilterChain */
$parts = array();
foreach ($filter->filters() as $filterPart) {
$part = $this->renderFilter($filterPart, $level + 1);
if ($part) {
$parts[] = $part;
}
}
if (empty($parts)) {
return '';
}
$format = '%1$s(%2$s)';
if (count($parts) === 1) {
$format = '%2$s';
}
if ($level === 0) {
$format = '(' . $format . ')';
}
return sprintf($format, $filter->getOperatorSymbol(), implode(')(', $parts));
}
/**
* Render and return a valid LDAP filter expression of the given filter
*
* @param FilterExpression $filter
*
* @return string
*/
protected function renderFilterExpression(FilterExpression $filter)
{
$column = $filter->getColumn();
$sign = $filter->getSign();
$expression = $filter->getExpression();
$format = '%1$s%2$s%3$s';
if ($expression === null || $expression === true) {
$expression = '*';
} elseif (is_array($expression)) {
$seqFormat = '|(%s)';
if ($sign === '!=') {
$seqFormat = '!(' . $seqFormat . ')';
$sign = '=';
}
$seqParts = array();
foreach ($expression as $expressionValue) {
$seqParts[] = sprintf(
$format,
LdapUtils::quoteForSearch($column),
$sign,
LdapUtils::quoteForSearch($expressionValue, true)
);
}
return sprintf($seqFormat, implode(')(', $seqParts));
}
if ($sign === '!=') {
$format = '!(%1$s=%3$s)';
}
return sprintf(
$format,
LdapUtils::quoteForSearch($column),
$sign,
LdapUtils::quoteForSearch($expression, true)
);
}
/**
* Inspect if this LDAP Connection is working as expected
*

View File

@ -4,23 +4,12 @@
namespace Icinga\Protocol\Ldap;
use Icinga\Data\SimpleQuery;
use Icinga\Data\Filter\Filter;
use Icinga\Exception\NotImplementedError;
/**
* LDAP query class
*/
class LdapQuery extends SimpleQuery
{
/**
* This query's filters
*
* Currently just a basic key/value pair based array. Can be removed once Icinga\Data\Filter is supported.
*
* @var array
*/
protected $filters;
/**
* The base dn being used for this query
*
@ -54,7 +43,6 @@ class LdapQuery extends SimpleQuery
*/
protected function init()
{
$this->filters = array();
$this->usePagedResults = false;
}
@ -157,47 +145,10 @@ class LdapQuery extends SimpleQuery
*/
public function from($target, array $fields = null)
{
$this->filters['objectClass'] = $target;
$this->where('objectClass', $target);
return parent::from($target, $fields);
}
/**
* Add a new filter to the query
*
* @param string $condition Column to search in
* @param mixed $value Value to look for (asterisk wildcards are allowed)
*
* @return $this
*/
public function where($condition, $value = null)
{
$this->filters[$condition] = $value;
return $this;
}
public function getFilter()
{
throw new NotImplementedError('Support for Icinga\Data\Filter is still missing. Use $this->where() instead');
}
public function addFilter(Filter $filter)
{
// TODO: This should be considered a quick fix only.
// Drop this entirely once support for Icinga\Data\Filter is available
if ($filter->isExpression()) {
$this->where($filter->getColumn(), $filter->getExpression());
} elseif ($filter->isChain()) {
foreach ($filter->filters() as $chainOrExpression) {
$this->addFilter($chainOrExpression);
}
}
}
public function setFilter(Filter $filter)
{
throw new NotImplementedError('Support for Icinga\Data\Filter is still missing. Use $this->where() instead');
}
/**
* Fetch result as tree
*
@ -249,33 +200,13 @@ class LdapQuery extends SimpleQuery
}
/**
* Return the LDAP filter to be applied on this query
* Render and return this query's filter
*
* @return string
*
* @throws LdapException In case the objectClass filter does not exist
*/
protected function renderFilter()
public function renderFilter()
{
if (! isset($this->filters['objectClass'])) {
throw new LdapException('Object class is mandatory');
}
$parts = array();
foreach ($this->filters as $key => $value) {
$parts[] = sprintf(
'%s=%s',
LdapUtils::quoteForSearch($key),
LdapUtils::quoteForSearch($value, true)
);
}
if (count($parts) > 1) {
$filter = '(&(' . implode(')(', $parts) . '))';
} else {
$filter = '(' . $parts[0] . ')';
}
$filter = $this->ds->renderFilter($this->filter);
if ($this->nativeFilter) {
$filter = '(&(' . $this->nativeFilter . ')' . $filter . ')';
}