LDAP-Auth backend config: Add support for custom LDAP filter rules

refs #8365
This commit is contained in:
Johannes Meyer 2015-03-11 09:52:14 +01:00
parent 0758be4af1
commit 39a74c4f3d
5 changed files with 81 additions and 19 deletions

View File

@ -55,7 +55,7 @@ class LdapBackendForm extends Form
'required' => true,
'label' => $this->translate('Backend Name'),
'description' => $this->translate(
'The name of this authentication provider that is used to differentiate it from others'
'The name of this authentication provider that is used to differentiate it from others.'
)
)
);
@ -64,8 +64,10 @@ class LdapBackendForm extends Form
'resource',
array(
'required' => true,
'label' => $this->translate('LDAP Resource'),
'description' => $this->translate('The resource to use for authenticating with this provider'),
'label' => $this->translate('LDAP Connection'),
'description' => $this->translate(
'The LDAP connection to use for authenticating with this provider.'
),
'multiOptions' => false === empty($this->resources)
? array_combine($this->resources, $this->resources)
: array()
@ -77,10 +79,40 @@ class LdapBackendForm extends Form
array(
'required' => true,
'label' => $this->translate('LDAP User Object Class'),
'description' => $this->translate('The object class used for storing users on the ldap server'),
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
'value' => 'inetOrgPerson'
)
);
$this->addElement(
'text',
'filter',
array(
'allowEmpty' => true,
'label' => $this->translate('LDAP Filter'),
'description' => $this->translate(
'An additional filter to use when looking up users using the specified connection. '
. 'Leave empty to not to use any additional filter rules.'
),
'requirement' => $this->translate(
'The filter needs to be expressed as standard LDAP expression, without'
. ' outer parentheses. (e.g. &(foo=bar)(bar=foo) or foo=bar)'
),
'validators' => array(
array(
'Callback',
false,
array(
'callback' => function ($v) {
return strpos($v, '(') !== 0;
},
'messages' => array(
'callbackValue' => $this->translate('The filter must not be wrapped in parantheses.')
)
)
)
)
)
);
$this->addElement(
'text',
'user_name_attribute',
@ -88,7 +120,7 @@ class LdapBackendForm extends Form
'required' => true,
'label' => $this->translate('LDAP User Name Attribute'),
'description' => $this->translate(
'The attribute name used for storing the user name on the ldap server'
'The attribute name used for storing the user name on the LDAP server.'
),
'value' => 'uid'
)
@ -106,10 +138,10 @@ class LdapBackendForm extends Form
'base_dn',
array(
'required' => false,
'label' => $this->translate('Base DN'),
'label' => $this->translate('LDAP Base DN'),
'description' => $this->translate(
'The path where users can be found on the ldap server. Leave ' .
'empty to select all users available on the specified resource.'
'The path where users can be found on the LDAP server. Leave ' .
'empty to select all users available using the specified connection.'
)
)
);
@ -142,11 +174,17 @@ class LdapBackendForm extends Form
ResourceFactory::createResource($form->getResourceConfig()),
$form->getElement('user_class')->getValue(),
$form->getElement('user_name_attribute')->getValue(),
$form->getElement('base_dn')->getValue()
$form->getElement('base_dn')->getValue(),
$form->getElement('filter')->getValue()
);
$ldapUserBackend->assertAuthenticationPossible();
} catch (AuthenticationException $e) {
if (($previous = $e->getPrevious()) !== null) {
$form->addError($previous->getMessage());
} else {
$form->addError($e->getMessage());
}
return false;
} catch (Exception $e) {
$form->addError(sprintf($form->translate('Unable to validate authentication: %s'), $e->getMessage()));

View File

@ -9,6 +9,7 @@ use Icinga\Protocol\Ldap\Query;
use Icinga\Protocol\Ldap\Connection;
use Icinga\Exception\AuthenticationException;
use Icinga\Protocol\Ldap\Exception as LdapException;
use Icinga\Protocol\Ldap\Expression;
class LdapUserBackend extends UserBackend
{
@ -25,14 +26,23 @@ class LdapUserBackend extends UserBackend
protected $userNameAttribute;
protected $customFilter;
protected $groupOptions;
public function __construct(Connection $conn, $userClass, $userNameAttribute, $baseDn, $groupOptions = null)
{
public function __construct(
Connection $conn,
$userClass,
$userNameAttribute,
$baseDn,
$cutomFilter,
$groupOptions = null
) {
$this->conn = $conn;
$this->baseDn = trim($baseDn) !== '' ? $baseDn : $conn->getDN();
$this->baseDn = trim($baseDn) ?: $conn->getDN();
$this->userClass = $userClass;
$this->userNameAttribute = $userNameAttribute;
$this->customFilter = trim($cutomFilter);
$this->groupOptions = $groupOptions;
}
@ -43,12 +53,18 @@ class LdapUserBackend extends UserBackend
*/
protected function selectUsers()
{
return $this->conn->select()->setBase($this->baseDn)->from(
$query = $this->conn->select()->setBase($this->baseDn)->from(
$this->userClass,
array(
$this->userNameAttribute
)
);
if ($this->customFilter) {
$query->addFilter(new Expression($this->customFilter));
}
return $query;
}
/**
@ -88,9 +104,10 @@ class LdapUserBackend extends UserBackend
if ($result === null) {
throw new AuthenticationException(
'No objects with objectClass="%s" in DN="%s" found.',
'No objects with objectClass="%s" in DN="%s" found. (Filter: %s)',
$this->userClass,
$this->baseDn
$this->baseDn,
$this->customFilter ?: 'None'
);
}

View File

@ -103,6 +103,7 @@ abstract class UserBackend implements Countable
$backendConfig->get('user_class', 'user'),
$backendConfig->get('user_name_attribute', 'sAMAccountName'),
$backendConfig->get('base_dn', $resource->getDN()),
$backendConfig->get('filter'),
$groupOptions
);
break;
@ -130,6 +131,7 @@ abstract class UserBackend implements Countable
$backendConfig->user_class,
$backendConfig->user_name_attribute,
$backendConfig->get('base_dn', $resource->getDN()),
$backendConfig->get('filter'),
$groupOptions
);
break;

View File

@ -272,7 +272,8 @@ class AdminAccountPage extends Form
ResourceFactory::createResource(new ConfigObject($this->resourceConfig)),
$this->backendConfig['user_class'],
$this->backendConfig['user_name_attribute'],
$this->backendConfig['base_dn']
$this->backendConfig['base_dn'],
$this->backendConfig['filter']
);
} else {
throw new LogicException(

View File

@ -126,11 +126,15 @@ class AuthenticationStep extends Step
. '</tr>'
. ($authType === 'ldap' ? (
'<tr>'
. '<td><strong>' . t('User Object Class') . '</strong></td>'
. '<td><strong>' . mt('setup', 'User Object Class') . '</strong></td>'
. '<td>' . $this->data['backendConfig']['user_class'] . '</td>'
. '</tr>'
. '<tr>'
. '<td><strong>' . t('User Name Attribute') . '</strong></td>'
. '<td><strong>' . mt('setup', 'Custom Filter') . '</strong></td>'
. '<td>' . trim($this->data['backendConfig']['filter']) ?: t('None', 'auth.ldap.filter') . '</td>'
. '</tr>'
. '<tr>'
. '<td><strong>' . mt('setup', 'User Name Attribute') . '</strong></td>'
. '<td>' . $this->data['backendConfig']['user_name_attribute'] . '</td>'
. '</tr>'
) : ($authType === 'external' ? (