mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-27 07:44:04 +02:00
Merge branch 'feature/allow-to-list-groups-from-a-ldap-backend-9772'
resolves #9772 fixes #9950
This commit is contained in:
commit
f6e67670e6
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use Icinga\Data\Extensible;
|
use Icinga\Data\Extensible;
|
||||||
use Icinga\Data\Updatable;
|
use Icinga\Data\Updatable;
|
||||||
|
use Icinga\Data\Selectable;
|
||||||
|
|
||||||
$extensible = $this->hasPermission('config/authentication/groups/add') && $backend instanceof Extensible;
|
$extensible = $this->hasPermission('config/authentication/groups/add') && $backend instanceof Extensible;
|
||||||
|
|
||||||
@ -67,7 +68,22 @@ foreach ($members as $member): ?>
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="member-name"><?= $this->escape($member->user_name); ?></td>
|
<td class="member-name">
|
||||||
|
<?php if (
|
||||||
|
$this->hasPermission('config/authentication/users/show')
|
||||||
|
&& ($userBackend = $backend->getUserBackend()) !== null
|
||||||
|
&& $userBackend instanceof Selectable
|
||||||
|
): ?>
|
||||||
|
<?= $this->qlink($member->user_name, 'user/show', array(
|
||||||
|
'backend' => $userBackend->getName(),
|
||||||
|
'user' => $member->user_name
|
||||||
|
), array(
|
||||||
|
'title' => sprintf($this->translate('Show detailed information about %s'), $member->user_name)
|
||||||
|
)); ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= $this->escape($member->user_name); ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</td>
|
||||||
<?php if (isset($removeForm)): ?>
|
<?php if (isset($removeForm)): ?>
|
||||||
<td class="member-remove" data-base-target="_self">
|
<td class="member-remove" data-base-target="_self">
|
||||||
<?php $removeForm->getElement('user_name')->setValue($member->user_name); echo $removeForm; ?>
|
<?php $removeForm->getElement('user_name')->setValue($member->user_name); echo $removeForm; ?>
|
||||||
|
@ -12,10 +12,16 @@ use Icinga\Protocol\Ldap\Expression;
|
|||||||
use Icinga\Repository\LdapRepository;
|
use Icinga\Repository\LdapRepository;
|
||||||
use Icinga\Repository\RepositoryQuery;
|
use Icinga\Repository\RepositoryQuery;
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use Icinga\Application\Logger;
|
|
||||||
|
|
||||||
class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBackendInterface
|
class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The user backend being associated with this user group backend
|
||||||
|
*
|
||||||
|
* @var LdapUserBackend
|
||||||
|
*/
|
||||||
|
protected $userBackend;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base DN to use for a user query
|
* The base DN to use for a user query
|
||||||
*
|
*
|
||||||
@ -105,84 +111,26 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normed attribute names based on known LDAP environments
|
* Set the user backend to be associated with this user group backend
|
||||||
*
|
*
|
||||||
* @var array
|
* @param LdapUserBackend $backend
|
||||||
*/
|
|
||||||
protected $normedAttributes = array(
|
|
||||||
'uid' => 'uid',
|
|
||||||
'gid' => 'gid',
|
|
||||||
'user' => 'user',
|
|
||||||
'group' => 'group',
|
|
||||||
'member' => 'member',
|
|
||||||
'inetorgperson' => 'inetOrgPerson',
|
|
||||||
'samaccountname' => 'sAMAccountName'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of this repository
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The datasource being used
|
|
||||||
*
|
|
||||||
* @var Connection
|
|
||||||
*/
|
|
||||||
protected $ds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new LDAP repository object
|
|
||||||
*
|
|
||||||
* @param Connection $ds The data source to use
|
|
||||||
*/
|
|
||||||
public function __construct($ds)
|
|
||||||
{
|
|
||||||
$this->ds = $ds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the given attribute name normed to known LDAP enviroments, if possible
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function getNormedAttribute($name)
|
|
||||||
{
|
|
||||||
$loweredName = strtolower($name);
|
|
||||||
if (array_key_exists($loweredName, $this->normedAttributes)) {
|
|
||||||
return $this->normedAttributes[$loweredName];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set this repository's name
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setName($name)
|
public function setUserBackend(LdapUserBackend $backend)
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->userBackend = $backend;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this repository's name
|
* Return the user backend being associated with this user group backend
|
||||||
*
|
*
|
||||||
* In case no name has been explicitly set yet, the class name is returned.
|
* @return LdapUserBackend
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getName()
|
public function getUserBackend()
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->userBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -453,7 +401,6 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
$lastModifiedAttribute = 'modifyTimestamp';
|
$lastModifiedAttribute = 'modifyTimestamp';
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jom): Fetching memberships does not work currently, we'll need some aggregate functionality!
|
|
||||||
$columns = array(
|
$columns = array(
|
||||||
'group' => $this->groupNameAttribute,
|
'group' => $this->groupNameAttribute,
|
||||||
'group_name' => $this->groupNameAttribute,
|
'group_name' => $this->groupNameAttribute,
|
||||||
@ -492,13 +439,37 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
if ($this->groupClass === null) {
|
if ($this->groupClass === null) {
|
||||||
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
|
throw new ProgrammingError('It is required to set the objectClass where to look for groups first');
|
||||||
}
|
}
|
||||||
|
if ($this->groupMemberAttribute === null) {
|
||||||
|
throw new ProgrammingError('It is required to set a attribute name where to find a group\'s members first');
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
$rules = array(
|
||||||
$this->groupClass => array(
|
$this->groupClass => array(
|
||||||
'created_at' => 'generalized_time',
|
'created_at' => 'generalized_time',
|
||||||
'last_modified' => 'generalized_time'
|
'last_modified' => 'generalized_time'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
if (! $this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
|
||||||
|
$rules[$this->groupClass][] = 'user_name';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the uid for the given distinguished name
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
*/
|
||||||
|
protected function retrieveUserName($dn)
|
||||||
|
{
|
||||||
|
return $this->ds
|
||||||
|
->select()
|
||||||
|
->from('*', array($this->userNameAttribute))
|
||||||
|
->setBase($dn)
|
||||||
|
->fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -524,6 +495,27 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
return $table;
|
return $table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that the given column is a valid query target and return it or the actual name if it's an alias
|
||||||
|
*
|
||||||
|
* @param string $table The table where to look for the column or alias
|
||||||
|
* @param string $name The name or alias of the column to validate
|
||||||
|
* @param RepositoryQuery $query An optional query to pass as context
|
||||||
|
*
|
||||||
|
* @return string The given column's name
|
||||||
|
*
|
||||||
|
* @throws QueryException In case the given column is not a valid query column
|
||||||
|
*/
|
||||||
|
public function requireQueryColumn($table, $name, RepositoryQuery $query = null)
|
||||||
|
{
|
||||||
|
$column = parent::requireQueryColumn($table, $name, $query);
|
||||||
|
if ($name === 'user_name' && $query !== null) {
|
||||||
|
$query->getQuery()->setUnfoldAttribute('user_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $column;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the groups the given user is a member of
|
* Return the groups the given user is a member of
|
||||||
*
|
*
|
||||||
@ -533,43 +525,37 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
*/
|
*/
|
||||||
public function getMemberships(User $user)
|
public function getMemberships(User $user)
|
||||||
{
|
{
|
||||||
if ($this->groupClass === 'posixGroup') {
|
if ($this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
|
||||||
// Posix group only uses simple user name
|
$queryValue = $user->getUsername();
|
||||||
$userDn = $user->getUsername();
|
} elseif (($queryValue = $user->getAdditional('ldap_dn')) === null) {
|
||||||
} else {
|
$userQuery = $this->ds
|
||||||
// LDAP groups use the complete DN
|
->select()
|
||||||
if (($userDn = $user->getAdditional('ldap_dn')) === null) {
|
->from($this->userClass)
|
||||||
$userQuery = $this->ds
|
->where($this->userNameAttribute, $user->getUsername())
|
||||||
->select()
|
->setBase($this->userBaseDn)
|
||||||
->from($this->userClass)
|
->setUsePagedResults(false);
|
||||||
->where($this->userNameAttribute, $user->getUsername())
|
if ($this->userFilter) {
|
||||||
->setBase($this->userBaseDn)
|
$userQuery->where(new Expression($this->userFilter));
|
||||||
->setUsePagedResults(false);
|
}
|
||||||
if ($this->userFilter) {
|
|
||||||
$userQuery->where(new Expression($this->userFilter));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($userDn = $userQuery->fetchDn()) === null) {
|
if (($queryValue = $userQuery->fetchDn()) === null) {
|
||||||
return array();
|
return array();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$groupQuery = $this->ds
|
$groupQuery = $this->ds
|
||||||
->select()
|
->select()
|
||||||
->from($this->groupClass, array($this->groupNameAttribute))
|
->from($this->groupClass, array($this->groupNameAttribute))
|
||||||
->where($this->groupMemberAttribute, $userDn)
|
->where($this->groupMemberAttribute, $queryValue)
|
||||||
->setBase($this->groupBaseDn);
|
->setBase($this->groupBaseDn);
|
||||||
if ($this->groupFilter) {
|
if ($this->groupFilter) {
|
||||||
$groupQuery->where(new Expression($this->groupFilter));
|
$groupQuery->where(new Expression($this->groupFilter));
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Fetching groups for user %s using filter %s.', $user->getUsername(), $groupQuery->__toString());
|
|
||||||
$groups = array();
|
$groups = array();
|
||||||
foreach ($groupQuery as $row) {
|
foreach ($groupQuery as $row) {
|
||||||
$groups[] = $row->{$this->groupNameAttribute};
|
$groups[] = $row->{$this->groupNameAttribute};
|
||||||
}
|
}
|
||||||
Logger::debug('Fetched %d groups: %s.', count($groups), join(', ', $groups));
|
|
||||||
|
|
||||||
return $groups;
|
return $groups;
|
||||||
}
|
}
|
||||||
@ -610,6 +596,7 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->setUserBackend($userBackend);
|
||||||
$defaults->merge(array(
|
$defaults->merge(array(
|
||||||
'user_base_dn' => $userBackend->getBaseDn(),
|
'user_base_dn' => $userBackend->getBaseDn(),
|
||||||
'user_class' => $userBackend->getUserClass(),
|
'user_class' => $userBackend->getUserClass(),
|
||||||
@ -661,4 +648,4 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
|
|||||||
'group_member_attribute' => 'member'
|
'group_member_attribute' => 'member'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -358,9 +358,25 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
*/
|
*/
|
||||||
public function count(LdapQuery $query)
|
public function count(LdapQuery $query)
|
||||||
{
|
{
|
||||||
$ds = $this->getConnection();
|
|
||||||
$this->bind();
|
$this->bind();
|
||||||
|
|
||||||
|
if (($unfoldAttribute = $query->getUnfoldAttribute()) !== null) {
|
||||||
|
$desiredColumns = $query->getColumns();
|
||||||
|
if (isset($desiredColumns[$unfoldAttribute])) {
|
||||||
|
$fields = array($unfoldAttribute => $desiredColumns[$unfoldAttribute]);
|
||||||
|
} elseif (in_array($unfoldAttribute, $desiredColumns, true)) {
|
||||||
|
$fields = array($unfoldAttribute);
|
||||||
|
} else {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
'The attribute used to unfold a query\'s result must be selected'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = $this->runQuery($query, $fields);
|
||||||
|
return count($res);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ds = $this->getConnection();
|
||||||
$results = @ldap_search(
|
$results = @ldap_search(
|
||||||
$ds,
|
$ds,
|
||||||
$query->getBase() ?: $this->getDn(),
|
$query->getBase() ?: $this->getDn(),
|
||||||
@ -658,7 +674,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
protected function runQuery(LdapQuery $query, array $fields = null)
|
protected function runQuery(LdapQuery $query, array $fields = null)
|
||||||
{
|
{
|
||||||
$limit = $query->getLimit();
|
$limit = $query->getLimit();
|
||||||
$offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
|
$offset = $query->hasOffset() ? $query->getOffset() : 0;
|
||||||
|
|
||||||
if ($fields === null) {
|
if ($fields === null) {
|
||||||
$fields = $query->getColumns();
|
$fields = $query->getColumns();
|
||||||
@ -711,13 +727,41 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
$count = 0;
|
$count = 0;
|
||||||
$entries = array();
|
$entries = array();
|
||||||
$entry = ldap_first_entry($ds, $results);
|
$entry = ldap_first_entry($ds, $results);
|
||||||
|
$unfoldAttribute = $query->getUnfoldAttribute();
|
||||||
do {
|
do {
|
||||||
$count += 1;
|
if ($unfoldAttribute) {
|
||||||
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
$rows = $this->cleanupAttributes(
|
||||||
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
|
||||||
ldap_get_attributes($ds, $entry),
|
ldap_get_attributes($ds, $entry),
|
||||||
array_flip($fields)
|
array_flip($fields),
|
||||||
|
$unfoldAttribute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (is_array($rows)) {
|
||||||
|
// TODO: Register the DN the same way as a section name in the ArrayDatasource!
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
||||||
|
ldap_get_attributes($ds, $entry),
|
||||||
|
array_flip($fields)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while ((! $serverSorting || $limit === 0 || $limit !== count($entries))
|
} while ((! $serverSorting || $limit === 0 || $limit !== count($entries))
|
||||||
&& ($entry = ldap_next_entry($ds, $entry))
|
&& ($entry = ldap_next_entry($ds, $entry))
|
||||||
@ -754,7 +798,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
}
|
}
|
||||||
|
|
||||||
$limit = $query->getLimit();
|
$limit = $query->getLimit();
|
||||||
$offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
|
$offset = $query->hasOffset() ? $query->getOffset() : 0;
|
||||||
$queryString = (string) $query;
|
$queryString = (string) $query;
|
||||||
$base = $query->getBase() ?: $this->rootDn;
|
$base = $query->getBase() ?: $this->rootDn;
|
||||||
|
|
||||||
@ -776,6 +820,7 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
$count = 0;
|
$count = 0;
|
||||||
$cookie = '';
|
$cookie = '';
|
||||||
$entries = array();
|
$entries = array();
|
||||||
|
$unfoldAttribute = $query->getUnfoldAttribute();
|
||||||
do {
|
do {
|
||||||
// Do not request the pagination control as a critical extension, as we want the
|
// Do not request the pagination control as a critical extension, as we want the
|
||||||
// server to return results even if the paged search request cannot be satisfied
|
// server to return results even if the paged search request cannot be satisfied
|
||||||
@ -826,12 +871,39 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
|
|
||||||
$entry = ldap_first_entry($ds, $results);
|
$entry = ldap_first_entry($ds, $results);
|
||||||
do {
|
do {
|
||||||
$count += 1;
|
if ($unfoldAttribute) {
|
||||||
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
$rows = $this->cleanupAttributes(
|
||||||
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
|
||||||
ldap_get_attributes($ds, $entry),
|
ldap_get_attributes($ds, $entry),
|
||||||
array_flip($fields)
|
array_flip($fields),
|
||||||
|
$unfoldAttribute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (is_array($rows)) {
|
||||||
|
// TODO: Register the DN the same way as a section name in the ArrayDatasource!
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($serverSorting && $limit > 0 && $limit === count($entries)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$count += 1;
|
||||||
|
if (! $serverSorting || $offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(
|
||||||
|
ldap_get_attributes($ds, $entry),
|
||||||
|
array_flip($fields)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (
|
} while (
|
||||||
(! $serverSorting || $limit === 0 || $limit !== count($entries))
|
(! $serverSorting || $limit === 0 || $limit !== count($entries))
|
||||||
@ -861,9 +933,6 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
// the server: https://www.ietf.org/rfc/rfc2696.txt
|
// the server: https://www.ietf.org/rfc/rfc2696.txt
|
||||||
ldap_control_paged_result($ds, 0, false, $cookie);
|
ldap_control_paged_result($ds, 0, false, $cookie);
|
||||||
ldap_search($ds, $base, $queryString); // Returns no entries, due to the page size
|
ldap_search($ds, $base, $queryString); // Returns no entries, due to the page size
|
||||||
} else {
|
|
||||||
// Reset the paged search request so that subsequent requests succeed
|
|
||||||
ldap_control_paged_result($ds, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $serverSorting && $query->hasOrder()) {
|
if (! $serverSorting && $query->hasOrder()) {
|
||||||
@ -879,14 +948,16 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
/**
|
/**
|
||||||
* Clean up the given attributes and return them as simple object
|
* Clean up the given attributes and return them as simple object
|
||||||
*
|
*
|
||||||
* Applies column aliases, aggregates multi-value attributes as array and sets null for each missing attribute.
|
* Applies column aliases, aggregates/unfolds multi-value attributes
|
||||||
|
* as array and sets null for each missing attribute.
|
||||||
*
|
*
|
||||||
* @param array $attributes
|
* @param array $attributes
|
||||||
* @param array $requestedFields
|
* @param array $requestedFields
|
||||||
|
* @param string $unfoldAttribute
|
||||||
*
|
*
|
||||||
* @return object
|
* @return object|array An array in case the object has been unfolded
|
||||||
*/
|
*/
|
||||||
public function cleanupAttributes($attributes, array $requestedFields)
|
public function cleanupAttributes($attributes, array $requestedFields, $unfoldAttribute = null)
|
||||||
{
|
{
|
||||||
// In case the result contains attributes with a differing case than the requested fields, it is
|
// In case the result contains attributes with a differing case than the requested fields, it is
|
||||||
// necessary to create another array to map attributes case insensitively to their requested counterparts.
|
// necessary to create another array to map attributes case insensitively to their requested counterparts.
|
||||||
@ -927,6 +998,24 @@ class LdapConnection implements Selectable, Inspectable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$unfoldAttribute !== null
|
||||||
|
&& isset($cleanedAttributes[$unfoldAttribute])
|
||||||
|
&& is_array($cleanedAttributes[$unfoldAttribute])
|
||||||
|
) {
|
||||||
|
$values = $cleanedAttributes[$unfoldAttribute];
|
||||||
|
unset($cleanedAttributes[$unfoldAttribute]);
|
||||||
|
$baseRow = (object) $cleanedAttributes;
|
||||||
|
$rows = array();
|
||||||
|
foreach ($values as $value) {
|
||||||
|
$row = clone $baseRow;
|
||||||
|
$row->{$unfoldAttribute} = $value;
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
return (object) $cleanedAttributes;
|
return (object) $cleanedAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,13 @@ class LdapQuery extends SimpleQuery
|
|||||||
*/
|
*/
|
||||||
protected $usePagedResults;
|
protected $usePagedResults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the attribute used to unfold the result
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $unfoldAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize this query
|
* Initialize this query
|
||||||
*/
|
*/
|
||||||
@ -90,6 +97,29 @@ class LdapQuery extends SimpleQuery
|
|||||||
return $this->usePagedResults;
|
return $this->usePagedResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the attribute to be used to unfold the result
|
||||||
|
*
|
||||||
|
* @param string $attributeName
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setUnfoldAttribute($attributeName)
|
||||||
|
{
|
||||||
|
$this->unfoldAttribute = $attributeName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the attribute to use to unfold the result
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUnfoldAttribute()
|
||||||
|
{
|
||||||
|
return $this->unfoldAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose an objectClass and the columns you are interested in
|
* Choose an objectClass and the columns you are interested in
|
||||||
*
|
*
|
||||||
|
@ -28,13 +28,27 @@ abstract class LdapRepository extends Repository
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $normedAttributes = array(
|
protected $normedAttributes = array(
|
||||||
'uid' => 'uid',
|
'uid' => 'uid',
|
||||||
'gid' => 'gid',
|
'gid' => 'gid',
|
||||||
'user' => 'user',
|
'user' => 'user',
|
||||||
'group' => 'group',
|
'group' => 'group',
|
||||||
'member' => 'member',
|
'member' => 'member',
|
||||||
'inetorgperson' => 'inetOrgPerson',
|
'memberuid' => 'memberUid',
|
||||||
'samaccountname' => 'sAMAccountName'
|
'posixgroup' => 'posixGroup',
|
||||||
|
'uniquemember' => 'uniqueMember',
|
||||||
|
'groupofnames' => 'groupOfNames',
|
||||||
|
'inetorgperson' => 'inetOrgPerson',
|
||||||
|
'samaccountname' => 'sAMAccountName',
|
||||||
|
'groupofuniquenames' => 'groupOfUniqueNames'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object attributes whose value is not distinguished name
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $ambiguousAttributes = array(
|
||||||
|
'posixGroup' => 'memberUid'
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,4 +77,17 @@ abstract class LdapRepository extends Repository
|
|||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Return whether the given object attribute's value is not a distinguished name
|
||||||
|
*
|
||||||
|
* @param string $objectClass
|
||||||
|
* @param string $attributeName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isAmbiguous($objectClass, $attributeName)
|
||||||
|
{
|
||||||
|
return isset($this->ambiguousAttributes[$objectClass][$attributeName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user