+
compact): ?>
- = $tabs; ?>
+ = $tabs; ?>
-
= $this->escape($user->user_name) ?>= $editLink ?>
-
-
- = $this->translate('State'); ?> |
- = $user->is_active === null ? '-' : ($user->is_active ? $this->translate('Active') : $this->translate('Inactive')); ?> |
-
-
- = $this->translate('Created at'); ?> |
- = $user->created_at === null ? '-' : $this->formatDateTime($user->created_at); ?> |
-
-
- = $this->translate('Last modified'); ?> |
- = $user->last_modified === null ? '-' : $this->formatDateTime($user->last_modified); ?> |
-
-
-
= $this->translate('Group Memberships'); ?>
+
= $this->escape($user->user_name) ?>= $editLink ?>
+
+
+ = $this->translate('State'); ?> |
+ = $user->is_active === null ? '-' : ($user->is_active ? $this->translate('Active') : $this->translate('Inactive')); ?> |
+
+
+ = $this->translate('Created at'); ?> |
+ = $user->created_at === null ? '-' : $this->formatDateTime($user->created_at); ?> |
+
+
+ = $this->translate('Last modified'); ?> |
+ = $user->last_modified === null ? '-' : $this->formatDateTime($user->last_modified); ?> |
+
+
compact): ?>
- = $this->sortBox; ?>
-
- = $this->limiter; ?>
- = $this->paginator; ?>
-compact): ?>
- = $this->filterEditor; ?>
+
= $this->translate('Group Memberships'); ?>
+
+ = $this->limiter; ?>
+ = $this->paginator; ?>
+ = $this->sortBox; ?>
+
+ = $this->filterEditor; ?>
-
-
+
+
= $this->qlink(
- $this->translate('Add User to Group') ,
+ $this->translate('Create New Membership'),
'user/createmembership',
- array('backend' => $backend->getName()),
array(
- 'class' => 'button-link',
- 'data-base-target' => '_next',
- 'icon' => 'plus',
- 'title' => $this->translate('Add user to user group')
+ 'backend' => $backend->getName(),
+ 'user' => $user->user_name
+ ),
+ array(
+ 'icon' => 'plus',
+ 'class' => 'button-link'
)
) ?>
-
-
-
-
-
-
-
- = $this->translate('Group'); ?> |
- = $this->translate('Cancel', 'group.membership'); ?> |
-
-
-
-
-
-
- hasPermission('config/authentication/groups/show') && $membership->backend instanceof Selectable): ?>
- = $this->qlink($membership->group_name, 'group/show', array(
- 'backend' => $membership->backend->getName(),
- 'group' => $membership->group_name
- ), array(
- 'title' => sprintf($this->translate('Show detailed information for group %s'), $membership->group_name)
- )); ?>
-
- = $this->escape($membership->group_name); ?>
-
- |
-
- backend instanceof Reducible): ?>
- = $removeForm->setAction($this->url('group/removemember', array(
- 'backend' => $membership->backend->getName(),
- 'group' => $membership->group_name
- ))); ?>
-
- -
-
- |
-
-
-hasResult()): ?>
-
-
-
-
= $this->translate('No memberships found matching the filter'); ?>
+
+hasResult()): ?>
+
= $this->translate('No memberships found matching the filter'); ?>
+
+
+
+
+
+ = $this->translate('Group'); ?> |
+ = $this->translate('Cancel', 'group.membership'); ?> |
+
+
+
+
+
+
+ hasPermission('config/authentication/groups/show') && $membership->backend instanceof Selectable): ?>
+ = $this->qlink($membership->group_name, 'group/show', array(
+ 'backend' => $membership->backend->getName(),
+ 'group' => $membership->group_name
+ ), array(
+ 'title' => sprintf($this->translate('Show detailed information for group %s'), $membership->group_name)
+ )); ?>
+
+ = $this->escape($membership->group_name); ?>
+
+ |
+
+ backend instanceof Reducible): ?>
+ = $removeForm->setAction($this->url('group/removemember', array(
+ 'backend' => $membership->backend->getName(),
+ 'group' => $membership->group_name
+ ))); ?>
+
+ -
+
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/library/Icinga/Authentication/User/DbUserBackend.php b/library/Icinga/Authentication/User/DbUserBackend.php
index c0c949fd7..e004a56c0 100644
--- a/library/Icinga/Authentication/User/DbUserBackend.php
+++ b/library/Icinga/Authentication/User/DbUserBackend.php
@@ -130,6 +130,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
*/
public function insert($table, array $bind)
{
+ $this->requireTable($table);
$bind['created_at'] = date('Y-m-d H:i:s');
$this->ds->insert(
$this->prependTablePrefix($table),
@@ -150,6 +151,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
*/
public function update($table, array $bind, Filter $filter = null)
{
+ $this->requireTable($table);
$bind['last_modified'] = date('Y-m-d H:i:s');
if ($filter) {
$filter = $this->requireFilter($table, $filter);
diff --git a/library/Icinga/Authentication/User/LdapUserBackend.php b/library/Icinga/Authentication/User/LdapUserBackend.php
index f3a852115..b5bd51f45 100644
--- a/library/Icinga/Authentication/User/LdapUserBackend.php
+++ b/library/Icinga/Authentication/User/LdapUserBackend.php
@@ -341,6 +341,27 @@ class LdapUserBackend extends LdapRepository implements UserBackendInterface, In
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;
+ }
+
/**
* Authenticate the given user
*
diff --git a/library/Icinga/Authentication/UserGroup/DbUserGroupBackend.php b/library/Icinga/Authentication/UserGroup/DbUserGroupBackend.php
index a114cc8d1..6f5c2e9dd 100644
--- a/library/Icinga/Authentication/UserGroup/DbUserGroupBackend.php
+++ b/library/Icinga/Authentication/UserGroup/DbUserGroupBackend.php
@@ -217,6 +217,18 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
return $memberships;
}
+ /**
+ * Return the name of the backend that is providing the given user
+ *
+ * @param string $username Currently unused
+ *
+ * @return null|string The name of the backend or null in case this information is not available
+ */
+ public function getUserBackendName($username)
+ {
+ return null; // TODO(10373): Store this to the database when inserting and fetch it here
+ }
+
/**
* Join group into group_membership
*
@@ -238,7 +250,7 @@ class DbUserGroupBackend extends DbRepository implements UserGroupBackendInterfa
*/
protected function joinGroupMembership(RepositoryQuery $query)
{
- $query->getQuery()->join(
+ $query->getQuery()->joinLeft(
$this->requireTable('group_membership'),
'g.id = gm.group_id',
array()
diff --git a/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php b/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
index 2aa615a84..9a4ab53c0 100644
--- a/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
+++ b/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php
@@ -5,6 +5,7 @@ namespace Icinga\Authentication\UserGroup;
use Icinga\Authentication\User\UserBackend;
use Icinga\Authentication\User\LdapUserBackend;
+use Icinga\Application\Logger;
use Icinga\Data\ConfigObject;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\ProgrammingError;
@@ -454,12 +455,48 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
)
);
if (! $this->isAmbiguous($this->groupClass, $this->groupMemberAttribute)) {
+ $rules['group_membership']['user_name'] = 'user_name';
+ $rules['group_membership']['user'] = 'user_name';
$rules['group']['user_name'] = 'user_name';
+ $rules['group']['user'] = 'user_name';
}
return $rules;
}
+ /**
+ * Return the distinguished name for the given uid or gid
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function persistUserName($name)
+ {
+ $userDn = $this->ds
+ ->select()
+ ->from($this->userClass, array())
+ ->where($this->userNameAttribute, $name)
+ ->setUsePagedResults(false)
+ ->fetchDn();
+ if ($userDn) {
+ return $userDn;
+ }
+
+ $groupDn = $this->ds
+ ->select()
+ ->from($this->groupClass, array())
+ ->where($this->groupNameAttribute, $name)
+ ->setUsePagedResults(false)
+ ->fetchDn();
+ if ($groupDn) {
+ return $groupDn;
+ }
+
+ Logger::debug('Unable to persist uid or gid "%s" in repository "%s". No DN found.', $name, $this->getName());
+ return $name;
+ }
+
/**
* Return the uid for the given distinguished name
*
@@ -564,6 +601,21 @@ class LdapUserGroupBackend extends LdapRepository implements UserGroupBackendInt
return $groups;
}
+ /**
+ * Return the name of the backend that is providing the given user
+ *
+ * @param string $username Unused
+ *
+ * @return null|string The name of the backend or null in case this information is not available
+ */
+ public function getUserBackendName($username)
+ {
+ $userBackend = $this->getUserBackend();
+ if ($userBackend !== null) {
+ return $userBackend->getName();
+ }
+ }
+
/**
* Apply the given configuration on this backend
*
diff --git a/library/Icinga/Authentication/UserGroup/UserGroupBackendInterface.php b/library/Icinga/Authentication/UserGroup/UserGroupBackendInterface.php
index a567d1f0a..31dd2c50d 100644
--- a/library/Icinga/Authentication/UserGroup/UserGroupBackendInterface.php
+++ b/library/Icinga/Authentication/UserGroup/UserGroupBackendInterface.php
@@ -34,4 +34,13 @@ interface UserGroupBackendInterface
* @return array
*/
public function getMemberships(User $user);
+
+ /**
+ * Return the name of the backend that is providing the given user
+ *
+ * @param string $username
+ *
+ * @return null|string The name of the backend or null in case this information is not available
+ */
+ public function getUserBackendName($username);
}
diff --git a/library/Icinga/Repository/DbRepository.php b/library/Icinga/Repository/DbRepository.php
index 89701cb9d..27144d097 100644
--- a/library/Icinga/Repository/DbRepository.php
+++ b/library/Icinga/Repository/DbRepository.php
@@ -297,6 +297,7 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
*/
public function insert($table, array $bind)
{
+ $this->requireTable($table);
$this->ds->insert($this->prependTablePrefix($table), $this->requireStatementColumns($table, $bind));
}
@@ -309,6 +310,8 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
*/
public function update($table, array $bind, Filter $filter = null)
{
+ $this->requireTable($table);
+
if ($filter) {
$filter = $this->requireFilter($table, $filter);
}
@@ -324,6 +327,8 @@ abstract class DbRepository extends Repository implements Extensible, Updatable,
*/
public function delete($table, Filter $filter = null)
{
+ $this->requireTable($table);
+
if ($filter) {
$filter = $this->requireFilter($table, $filter);
}
diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less
index 54430ef60..624b21eec 100644
--- a/public/css/icinga/main-content.less
+++ b/public/css/icinga/main-content.less
@@ -233,83 +233,6 @@ div.content.users {
}
}
-div.content.memberships {
- table.membership-list {
- th.membership-cancel {
- width: 8em;
- padding-right: 0.5em;
- text-align: right;
- }
-
- td.membership-cancel {
- text-align: right;
-
- form button.link-like {
- color: inherit;
- }
- }
- }
-
- p {
- margin-top: 0;
- }
-
- a.membership-create {
- display: block;
- margin-top: 1em;
- }
-}
-
-div.content.groups {
- table.group-list {
- th.group-remove {
- width: 8em;
- padding-right: 0.5em;
- text-align: right;
- }
-
- td.group-remove {
- text-align: right;
- }
- }
-
- p {
- margin-top: 0;
- }
-
- a.group-add {
- display: block;
- margin-top: 1em;
- }
-}
-
-div.content.members {
- table.member-list {
- th.member-remove {
- width: 8em;
- padding-right: 0.5em;
- text-align: right;
- }
-
- td.member-remove {
- text-align: right;
-
- form button.link-like {
- color: inherit;
- }
- }
- }
-
- p {
- margin-top: 0;
- }
-
- a.member-add {
- display: block;
- margin-top: 1em;
- }
-}
-
form.backend-selection {
float: right;