Skip to content

Commit

Permalink
Merge branch 'feature/allow-to-list-groups-from-a-ldap-backend-9772'
Browse files Browse the repository at this point in the history
resolves #9772
fixes #9950
  • Loading branch information
Johannes Meyer committed Sep 29, 2015
2 parents e20d791 + 35e62ae commit f6e6767
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 119 deletions.
18 changes: 17 additions & 1 deletion application/views/scripts/group/show.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use Icinga\Data\Extensible;
use Icinga\Data\Updatable;
use Icinga\Data\Selectable;

$extensible = $this->hasPermission('config/authentication/groups/add') && $backend instanceof Extensible;

Expand Down Expand Up @@ -67,7 +68,22 @@ foreach ($members as $member): ?>
<tbody>
<?php endif ?>
<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)): ?>
<td class="member-remove" data-base-target="_self">
<?php $removeForm->getElement('user_name')->setValue($member->user_name); echo $removeForm; ?>
Expand Down
173 changes: 80 additions & 93 deletions library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@
use Icinga\Repository\LdapRepository;
use Icinga\Repository\RepositoryQuery;
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
*
Expand Down Expand Up @@ -105,84 +111,26 @@ class LdapUserGroupBackend /*extends LdapRepository*/ implements UserGroupBacken
);

/**
* Normed attribute names based on known LDAP environments
*
* @var array
*/
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
* Set the user backend to be associated with this user group backend
*
* @param string $name
* @param LdapUserBackend $backend
*
* @return $this
*/
public function setName($name)
public function setUserBackend(LdapUserBackend $backend)
{
$this->name = $name;
$this->userBackend = $backend;
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 string
* @return LdapUserBackend
*/
public function getName()
public function getUserBackend()
{
return $this->name;
return $this->userBackend;
}

/**
Expand Down Expand Up @@ -453,7 +401,6 @@ protected function initializeQueryColumns()
$lastModifiedAttribute = 'modifyTimestamp';
}

// TODO(jom): Fetching memberships does not work currently, we'll need some aggregate functionality!
$columns = array(
'group' => $this->groupNameAttribute,
'group_name' => $this->groupNameAttribute,
Expand Down Expand Up @@ -492,13 +439,37 @@ protected function initializeConversionRules()
if ($this->groupClass === null) {
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(
'created_at' => '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();
}

/**
Expand All @@ -524,6 +495,27 @@ public function requireTable($table, RepositoryQuery $query = null)
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
*
Expand All @@ -533,43 +525,37 @@ public function requireTable($table, RepositoryQuery $query = null)
*/
public function getMemberships(User $user)
{
if ($this->groupClass === 'posixGroup') {
// Posix group only uses simple user name
$userDn = $user->getUsername();
} else {
// LDAP groups use the complete DN
if (($userDn = $user->getAdditional('ldap_dn')) === null) {
$userQuery = $this->ds
->select()
->from($this->userClass)
->where($this->userNameAttribute, $user->getUsername())
->setBase($this->userBaseDn)
->setUsePagedResults(false);
if ($this->userFilter) {
$userQuery->where(new Expression($this->userFilter));
}

if (($userDn = $userQuery->fetchDn()) === null) {
return array();
}
if ($this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
$queryValue = $user->getUsername();
} elseif (($queryValue = $user->getAdditional('ldap_dn')) === null) {
$userQuery = $this->ds
->select()
->from($this->userClass)
->where($this->userNameAttribute, $user->getUsername())
->setBase($this->userBaseDn)
->setUsePagedResults(false);
if ($this->userFilter) {
$userQuery->where(new Expression($this->userFilter));
}

if (($queryValue = $userQuery->fetchDn()) === null) {
return array();
}
}

$groupQuery = $this->ds
->select()
->from($this->groupClass, array($this->groupNameAttribute))
->where($this->groupMemberAttribute, $userDn)
->where($this->groupMemberAttribute, $queryValue)
->setBase($this->groupBaseDn);
if ($this->groupFilter) {
$groupQuery->where(new Expression($this->groupFilter));
}

Logger::debug('Fetching groups for user %s using filter %s.', $user->getUsername(), $groupQuery->__toString());
$groups = array();
foreach ($groupQuery as $row) {
$groups[] = $row->{$this->groupNameAttribute};
}
Logger::debug('Fetched %d groups: %s.', count($groups), join(', ', $groups));

return $groups;
}
Expand Down Expand Up @@ -610,6 +596,7 @@ public function setConfig(ConfigObject $config)
);
}

$this->setUserBackend($userBackend);
$defaults->merge(array(
'user_base_dn' => $userBackend->getBaseDn(),
'user_class' => $userBackend->getUserClass(),
Expand Down Expand Up @@ -661,4 +648,4 @@ public function getActiveDirectoryDefaults()
'group_member_attribute' => 'member'
));
}
}
}

0 comments on commit f6e6767

Please sign in to comment.