From 89d992278baf8e4fcd56255746f77a8f2850fdd9 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 3 Jun 2015 16:27:50 +0200 Subject: [PATCH] Introduce class LdapUserGroupBackend refs #743 --- .../UserGroup/LdapUserGroupBackend.php | 376 ++++++++++++++++++ .../UserGroup/UserGroupBackend.php | 24 ++ 2 files changed, 400 insertions(+) create mode 100644 library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php diff --git a/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php b/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php new file mode 100644 index 000000000..1e6addba2 --- /dev/null +++ b/library/Icinga/Authentication/UserGroup/LdapUserGroupBackend.php @@ -0,0 +1,376 @@ + array( + 'order' => 'asc' + ) + ); + + /** + * Set the base DN to use for a user query + * + * @param string $baseDn + * + * @return $this + */ + public function setUserBaseDn($baseDn) + { + if (($baseDn = trim($baseDn))) { + $this->userBaseDn = $baseDn; + } + + return $this; + } + + /** + * Return the base DN to use for a user query + * + * @return string + */ + public function getUserBaseDn() + { + return $this->userBaseDn; + } + + /** + * Set the base DN to use for a group query + * + * @param string $baseDn + * + * @return $this + */ + public function setGroupBaseDn($baseDn) + { + if (($baseDn = trim($baseDn))) { + $this->groupBaseDn = $baseDn; + } + + return $this; + } + + /** + * Return the base DN to use for a group query + * + * @return string + */ + public function getGroupBaseDn() + { + return $this->groupBaseDn; + } + + /** + * Set the objectClass where to look for users + * + * @param string $userClass + * + * @return $this + */ + public function setUserClass($userClass) + { + $this->userClass = $this->getNormedAttribute($userClass); + return $this; + } + + /** + * Return the objectClass where to look for users + * + * @return string + */ + public function getUserClass() + { + return $this->userClass; + } + + /** + * Set the objectClass where to look for groups + * + * Sets also the base table name for the underlying repository. + * + * @param string $groupClass + * + * @return $this + */ + public function setGroupClass($groupClass) + { + $this->baseTable = $this->groupClass = $this->getNormedAttribute($groupClass); + return $this; + } + + /** + * Return the objectClass where to look for groups + * + * @return string + */ + public function getGroupClass() + { + return $this->groupClass; + } + + /** + * Set the attribute name where to find a user's name + * + * @param string $userNameAttribute + * + * @return $this + */ + public function setUserNameAttribute($userNameAttribute) + { + $this->userNameAttribute = $this->getNormedAttribute($userNameAttribute); + return $this; + } + + /** + * Return the attribute name where to find a user's name + * + * @return string + */ + public function getUserNameAttribute() + { + return $this->userNameAttribute; + } + + /** + * Set the attribute name where to find a group's name + * + * @param string $groupNameAttribute + * + * @return $this + */ + public function setGroupNameAttribute($groupNameAttribute) + { + $this->groupNameAttribute = $this->getNormedAttribute($groupNameAttribute); + return $this; + } + + /** + * Return the attribute name where to find a group's name + * + * @return string + */ + public function getGroupNameAttribute() + { + return $this->groupNameAttribute; + } + + /** + * Set the attribute name where to find a group's member + * + * @param string $groupMemberAttribute + * + * @return $this + */ + public function setGroupMemberAttribute($groupMemberAttribute) + { + $this->groupMemberAttribute = $this->getNormedAttribute($groupMemberAttribute); + return $this; + } + + /** + * Return the attribute name where to find a group's member + * + * @return string + */ + public function getGroupMemberAttribute() + { + return $this->groupMemberAttribute; + } + + /** + * Return a new query for the given columns + * + * @param array $columns The desired columns, if null all columns will be queried + * + * @return RepositoryQuery + */ + public function select(array $columns = null) + { + $query = parent::select($columns); + $query->getQuery()->setBase($this->groupBaseDn); + return $query; + } + + /** + * Initialize this repository's query columns + * + * @return array + * + * @throws ProgrammingError In case either $this->groupNameAttribute or $this->groupClass has not been set yet + */ + protected function initializeQueryColumns() + { + if ($this->groupClass === null) { + throw new ProgrammingError('It is required to set the objectClass where to look for groups first'); + } + if ($this->groupNameAttribute === null) { + throw new ProgrammingError('It is required to set a attribute name where to find a group\'s name first'); + } + + if ($this->ds->getCapabilities()->hasAdOid()) { + $createdAtAttribute = 'whenCreated'; + $lastModifiedAttribute = 'whenChanged'; + } else { + $createdAtAttribute = 'createTimestamp'; + $lastModifiedAttribute = 'modifyTimestamp'; + } + + $columns = array( + 'group' => $this->groupNameAttribute, + 'group_name' => $this->groupNameAttribute, + 'user' => $this->groupMemberAttribute, + 'user_name' => $this->groupMemberAttribute, + 'created_at' => $createdAtAttribute, + 'last_modified' => $lastModifiedAttribute + ); + return array('group' => $columns, 'group_membership' => $columns); + } + + /** + * Initialize this repository's conversion rules + * + * @return array + * + * @throws ProgrammingError In case $this->groupClass has not been set yet + */ + protected function initializeConversionRules() + { + if ($this->groupClass === null) { + throw new ProgrammingError('It is required to set the objectClass where to look for groups first'); + } + + return array( + $this->groupClass => array( + 'created_at' => 'generalized_time', + 'last_modified' => 'generalized_time' + ) + ); + } + + /** + * Validate that the requested table exists + * + * This will return $this->groupClass in case $table equals "group" or "group_membership". + * + * @param string $table The table to validate + * @param RepositoryQuery $query An optional query to pass as context + * (unused by the base implementation) + * + * @return string + * + * @throws ProgrammingError In case the given table does not exist + */ + public function requireTable($table, RepositoryQuery $query = null) + { + $table = parent::requireTable($table, $query); + if ($table === 'group' || $table === 'group_membership') { + $table = $this->groupClass; + } + + return $table; + } + + /** + * Return the groups the given user is a member of + * + * @param User $user + * + * @return array + */ + public function getMemberships(User $user) + { + $userDn = $this->ds + ->select() + ->from($this->userClass) + ->where($this->userNameAttribute, $user->getUsername()) + ->setBase($this->userBaseDn) + ->setUsePagedResults(false) + ->fetchDn(); + + if ($userDn === null) { + return array(); + } + + $groupQuery = $this->ds + ->select() + ->from($this->groupClass, array($this->groupNameAttribute)) + ->where($this->groupMemberAttribute, $userDn) + ->setBase($this->groupBaseDn); + + $groups = array(); + foreach ($groupQuery as $row) { + $groups[] = $row->{$this->groupNameAttribute}; + } + + return $groups; + } +} diff --git a/library/Icinga/Authentication/UserGroup/UserGroupBackend.php b/library/Icinga/Authentication/UserGroup/UserGroupBackend.php index dd4900ea8..585f7c449 100644 --- a/library/Icinga/Authentication/UserGroup/UserGroupBackend.php +++ b/library/Icinga/Authentication/UserGroup/UserGroupBackend.php @@ -21,6 +21,8 @@ class UserGroupBackend */ protected static $defaultBackends = array( 'db', + 'ldap', + 'msldap', //'ini' ); @@ -156,6 +158,28 @@ class UserGroupBackend case 'ini': $backend = new IniUserGroupBackend($resource); break; + case 'ldap': + $backend = new LdapUserGroupBackend($resource); + $backend + ->setGroupBaseDn($backendConfig->base_dn) + ->setUserBaseDn($backendConfig->get('user_base_dn', $backend->getGroupBaseDn())) + ->setGroupClass($backendConfig->get('group_class', 'group')) + ->setUserClass($backendConfig->get('user_class', 'inetOrgPerson')) + ->setGroupNameAttribute($backendConfig->get('group_name_attribute', 'gid')) + ->setUserNameAttribute($backendConfig->get('user_name_attribute', 'uid')) + ->setGroupMemberAttribute($backendConfig->get('group_member_attribute', 'member')); + break; + case 'msldap': + $backend = new LdapUserGroupBackend($resource); + $backend + ->setGroupBaseDn($backendConfig->base_dn) + ->setUserBaseDn($backendConfig->get('user_base_dn', $backend->getGroupBaseDn())) + ->setGroupClass($backendConfig->get('group_class', 'group')) + ->setUserClass($backendConfig->get('user_class', 'user')) + ->setGroupNameAttribute($backendConfig->get('group_name_attribute', 'sAMAccountName')) + ->setUserNameAttribute($backendConfig->get('user_name_attribute', $backend->getGroupNameAttribute())) + ->setGroupMemberAttribute($backendConfig->get('group_member_attribute', 'member')); + break; } $backend->setName($name);