diff --git a/application/forms/Config/Authentication/LdapBackendForm.php b/application/forms/Config/Authentication/LdapBackendForm.php index 867f5658c..0ec2c3e38 100644 --- a/application/forms/Config/Authentication/LdapBackendForm.php +++ b/application/forms/Config/Authentication/LdapBackendForm.php @@ -170,13 +170,8 @@ class LdapBackendForm extends Form public static function isValidAuthenticationBackend(Form $form) { try { - $ldapUserBackend = new LdapUserBackend( - ResourceFactory::createResource($form->getResourceConfig()), - $form->getElement('user_class')->getValue(), - $form->getElement('user_name_attribute')->getValue(), - $form->getElement('base_dn')->getValue(), - $form->getElement('filter')->getValue() - ); + $ldapUserBackend = new LdapUserBackend(ResourceFactory::createResource($form->getResourceConfig())); + $ldapUserBackend->setConfig(new ConfigObject($form->getValues())); $ldapUserBackend->assertAuthenticationPossible(); } catch (AuthenticationException $e) { if (($previous = $e->getPrevious()) !== null) { diff --git a/library/Icinga/Authentication/User/LdapUserBackend.php b/library/Icinga/Authentication/User/LdapUserBackend.php index 8bc8f0222..9b2012b46 100644 --- a/library/Icinga/Authentication/User/LdapUserBackend.php +++ b/library/Icinga/Authentication/User/LdapUserBackend.php @@ -3,29 +3,55 @@ namespace Icinga\Authentication\User; -use Icinga\User; -use Icinga\Protocol\Ldap\Query; -use Icinga\Protocol\Ldap\Connection; +use Icinga\Data\ConfigObject; use Icinga\Exception\AuthenticationException; +use Icinga\Exception\ProgrammingError; +use Icinga\Repository\Repository; +use Icinga\Repository\RepositoryQuery; use Icinga\Protocol\Ldap\Exception as LdapException; use Icinga\Protocol\Ldap\Expression; +use Icinga\User; -class LdapUserBackend extends UserBackend +class LdapUserBackend extends Repository implements UserBackendInterface { /** - * Connection to the LDAP server + * The base DN to use for a query * - * @var Connection + * @var string */ - protected $conn; - protected $baseDn; + /** + * The objectClass where look for users + * + * @var string + */ protected $userClass; + /** + * The attribute name where to find a user's name + * + * @var string + */ protected $userNameAttribute; - protected $customFilter; + /** + * The custom LDAP filter to apply on search queries + * + * @var string + */ + protected $filter; + + /** + * The default sort rules to be applied on a query + * + * @var array + */ + protected $sortRules = array( + 'user_name' => array( + 'order' => 'asc' + ) + ); protected $groupOptions; @@ -41,20 +67,115 @@ class LdapUserBackend extends UserBackend 'samaccountname' => 'sAMAccountName' ); - public function __construct( - Connection $conn, - $userClass, - $userNameAttribute, - $baseDn, - $cutomFilter, - $groupOptions = null - ) { - $this->conn = $conn; - $this->baseDn = trim($baseDn) ?: $conn->getDN(); - $this->userClass = $this->getNormedAttribute($userClass); + /** + * Set the base DN to use for a query + * + * @param string $baseDn + * + * @return $this + */ + public function setBaseDn($baseDn) + { + if (($baseDn = trim($baseDn))) { + $this->baseDn = $baseDn; + } + + return $this; + } + + /** + * Return the base DN to use for a query + * + * @return string + */ + public function getBaseDn() + { + return $this->baseDn; + } + + /** + * Set the objectClass where to look for users + * + * Sets also the base table name for the underlying repository. + * + * @param string $userClass + * + * @return $this + */ + public function setUserClass($userClass) + { + $this->baseTable = $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 attribute name where to find a user's name + * + * @param string $userNameAttribute + * + * @return $this + */ + public function setUserNameAttribute($userNameAttribute) + { $this->userNameAttribute = $this->getNormedAttribute($userNameAttribute); - $this->customFilter = trim($cutomFilter); - $this->groupOptions = $groupOptions; + return $this; + } + + /** + * Return the attribute name where to find a user's name + * + * @return string + */ + public function getUserNameAttribute() + { + return $this->userNameAttribute; + } + + /** + * Set the custom LDAP filter to apply on search queries + * + * @param string $filter + * + * @return $this + */ + public function setFilter($filter) + { + if (($filter = trim($filter))) { + $this->filter = $filter; + } + + return $this; + } + + /** + * Return the custom LDAP filter to apply on search queries + * + * @return string + */ + public function getFilter() + { + return $this->filter; + } + + public function setGroupOptions(array $options) + { + $this->groupOptions = $options; + return $this; + } + + public function getGroupOptions() + { + return $this->groupOptions; } /** @@ -75,45 +196,69 @@ class LdapUserBackend extends UserBackend } /** - * Create a query to select all usernames + * Apply the given configuration to this backend * - * @return Query + * @param ConfigObject $config + * + * @return $this */ - protected function selectUsers() + public function setConfig(ConfigObject $config) { - $query = $this->conn->select()->setBase($this->baseDn)->from( - $this->userClass, - array( - $this->userNameAttribute - ) - ); + return $this + ->setBaseDn($config->base_dn) + ->setUserClass($config->user_class) + ->setUserNameAttribute($config->user_name_attribute) + ->setFilter($config->filter); + } - if ($this->customFilter) { - $query->addFilter(new Expression($this->customFilter)); + /** + * 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) + { + $this->initializeQueryColumns(); + + $query = parent::select($columns); + $query->getQuery()->setBase($this->baseDn); + if ($this->filter) { + $query->getQuery()->where(new Expression($this->filter)); } return $query; } /** - * Create a query filtered by the given username + * Initialize this repository's query columns * - * @param string $username - * - * @return Query + * @throws ProgrammingError In case either $this->userNameAttribute or $this->userClass has not been set yet */ - protected function selectUser($username) + protected function initializeQueryColumns() { - return $this->selectUsers()->setUsePagedResults(false)->where( - $this->userNameAttribute, - str_replace('*', '', $username) - ); + if ($this->queryColumns === null) { + if ($this->userClass === null) { + throw new ProgrammingError('It is required to set the objectClass where to look for users first'); + } + if ($this->userNameAttribute === null) { + throw new ProgrammingError('It is required to set a attribute name where to find a user\'s name first'); + } + + $this->queryColumns[$this->userClass] = array( + 'user_name' => $this->userNameAttribute, + 'is_active' => 'unknown', // msExchUserAccountControl == 2/512/514? <- AD LDAP + 'created_at' => 'whenCreated', // That's AD LDAP, + 'last_modified' => 'whenChanged' // what's OpenLDAP? + ); + } } /** * Probe the backend to test if authentication is possible * - * Try to bind to the backend and query all available users to check if: + * Try to bind to the backend and fetch a single user to check if: *