Add LDAP discovery pages

refs #7163
This commit is contained in:
Matthias Jentsch 2014-10-09 10:20:07 +02:00 committed by Johannes Meyer
parent df69fd2264
commit e29a568bff
6 changed files with 506 additions and 0 deletions

View File

@ -0,0 +1,214 @@
<?php
namespace Icinga\Form;
use Icinga\Application\Config;
use Icinga\Logger\Logger;
use Icinga\Protocol\Ldap\Exception as LdapException;
use Icinga\Protocol\Ldap\Connection;
use Icinga\Web\Request;
use Icinga\Protocol\Dns;
use Icinga\Web\Form\Element\Note;
use Icinga\Web\Form;
/**
* Form class for application-wide and logging specific settings
*/
class LdapDiscoveryForm extends Form
{
/**
* The discovered server settings
*
* @var array
*/
private $capabilities = null;
/**
* The discovered root_dn
*
* @var null
*/
private $namingContext = null;
/**
* The working domain name
*
* @var null
*/
private $domain = null;
/**
* The working port name
*
* @var int
*/
private $port = 389;
/**
* Initialize this page
*/
public function init()
{
$this->setName('form_ldap_discovery');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
$this->addElement(
'text',
'domain',
array(
'required' => true,
'label' => t('Search Domain'),
'description' => t('Search this domain for records of available servers.'),
)
);
if (false) {
$this->addElement(
new Note(
'additional_description',
array(
'value' => t('No Ldap servers found on this domain.'
. ' You can try to specify host and port and try again, or just skip this step and '
. 'configure the server manually.'
)
)
)
);
$this->addElement(
'text',
'hostname',
array(
'required' => false,
'label' => t('Host'),
'description' => t('IP or host name to search.'),
)
);
$this->addElement(
'text',
'port',
array(
'required' => false,
'label' => t('Port'),
'description' => t('Port', 389),
)
);
}
return $this;
}
public function isValid($data)
{
if (false === parent::isValid($data)) {
return false;
}
if ($this->discover($this->getValue('domain'))) {
return true;
}
return true;
}
private function discover($domain)
{
// Attempt 1: Connect to the domain directly
if ($this->discoverCapabilities(array(
'hostname' => $domain,
'port' => 389)
)) {
return true;
}
// Attempt 2: Discover all available ldap dns records and connect to the first one
$cap = false;
$records = array_merge(Dns::getSrvRecords($domain, 'ldap'), Dns::getSrvRecords($domain, 'ldaps'));
if (isset($records[0])) {
$record = $records[0];
if (isset($record['port'])) {
$cap = $this->discoverCapabilities(array(
'hostname' => $record['target'],
'port' => $record['port']
));
} else {
$cap = $this->discoverCapabilities(array(
'hostname' => $record['target'],
'port' => 389
));
}
}
return $cap;
}
private function discoverCapabilities($config)
{
$conn = new Connection(new Config($config));
try {
$conn->connect();
$this->capabilities = $conn->getCapabilities();
$this->namingContext = $conn->getDefaultNamingContext();
$this->port = $config['port'];
$this->domain = $config['hostname'];
return true;
} catch (LdapException $e) {
Logger::info(
'Ldap discovery for ' . $config['hostname'] . ':' . $config['port'] . ' failed: ' . $e->getMessage()
);
return false;
}
}
public function suggestResourceSettings()
{
if (! isset($this->capabilities)) {
return array();
}
if (isset($this->capabilities->msCapabilities->ActiveDirectoryOid)) {
return array(
'hostname' => $this->domain,
'port' => $this->port,
'root_dn' => $this->namingContext
);
} else {
return array(
'hostname' => $this->domain,
'port' => $this->port,
'root_dn' => $this->namingContext
);
}
}
public function hasSuggestion()
{
return isset($this->capabilities);
}
public function suggestBackendSettings()
{
if (! isset($this->capabilities)) {
return array();
}
if (isset($this->capabilities->msCapabilities->ActiveDirectoryOid)) {
return array(
'base_dn' => $this->namingContext,
'user_class' => 'user',
'user_name_attribute' => 'sAMAccountName'
);
} else {
return array(
'base_dn' => $this->namingContext,
'user_class' => 'inetOrgPerson',
'user_name_attribute' => 'uid'
);
}
}
public function isAd()
{
return isset($this->capabilities->msCapabilities->ActiveDirectoryOid);
}
}

View File

@ -23,6 +23,13 @@ class AuthBackendPage extends Form
*/
protected $config;
/**
* Suggested configuration settings
*
* @var array
*/
protected $suggestions;
/**
* Initialize this page
*/
@ -54,6 +61,19 @@ class AuthBackendPage extends Form
return new Zend_Config($this->config);
}
/**
* Set suggested configuration settings
*
* @param array $suggestions
*
* @return self
*/
public function setSuggestions(array $suggestions)
{
$this->suggestions = $suggestions;
return $this;
}
/**
* @see Form::createElements()
*/
@ -85,6 +105,10 @@ class AuthBackendPage extends Form
$backendForm = new DbBackendForm();
$backendForm->createElements($formData)->removeElement('resource');
} elseif ($this->config['type'] === 'ldap') {
if ($this->suggestions !== null) {
$formData += $this->suggestions;
}
$backendForm = new LdapBackendForm();
$backendForm->createElements($formData)->removeElement('resource');
} else { // $this->config['type'] === 'autologin'

View File

@ -0,0 +1,128 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Setup;
use Icinga\Protocol\Dns;
use Icinga\Web\Form;
use Icinga\Web\Form\Element\Note;
use Icinga\Form\LdapDiscoveryForm;
use Icinga\Form\Config\Resource\LdapResourceForm;
use Icinga\Web\Request;
/**
* Wizard page to define the connection details for a LDAP resource
*/
class LdapDiscoveryConfirmPage extends Form
{
const TYPE_AD = 'MS ActiveDirectory';
const TYPE_MISC = 'LDAP';
private $infoTemplate = <<< 'EOT'
<br/>
Found LDAP server on {domain}
<ul>
<li><b>Type:</b> {type}</li>
<li><b>Port:</b> {port}</li>
<li><b>Root DN:</b> {root_dn}</li>
<li><b>User-Class:</b> {user_class}</li>
<li><b>User-Attribue:</b> {user_attribute}</li>
</ul>
EOT;
/**
* The previous configuration
*
* @var array
*/
private $config;
/**
* Initialize this page
*/
public function init()
{
$this->setName('setup_ldap_discovery_confirm');
}
/**
* Set the resource configuration to use
*
* @param array $config
*
* @return self
*/
public function setResourceConfig(array $config)
{
$this->config = $config;
return $this;
}
/**
* Return the resource configuration as Zend_Config object
*
* @return Zend_Config
*/
public function getResourceConfig()
{
return new Zend_Config($this->config);
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
$resource = $this->config['resource'];
$backend = $this->config['backend'];
$html = $this->infoTemplate;
$html = str_replace('{domain}', $this->config['domain'], $html);
$html = str_replace('{type}', $this->config['type'], $html);
$html = str_replace('{hostname}', $resource['hostname'], $html);
$html = str_replace('{port}', $resource['port'], $html);
$html = str_replace('{root_dn}', $resource['root_dn'], $html);
$html = str_replace('{user_attribute}', $backend['user_name_attribute'], $html);
$html = str_replace('{user_class}', $backend['user_class'], $html);
$this->addElement(
new Note(
'suggestion',
array('value' => $html)
)
);
$this->addElement(
'checkbox',
'confirm',
array(
'value' => '1',
'label' => t('Use this configuration?')
)
);
}
/**
* Validate the given form data and check whether a BIND-request is successful
*
* @param array $data The data to validate
*
* @return bool
*/
public function isValid($data)
{
if (false === parent::isValid($data)) {
return false;
}
return true;
}
public function getValues($suppressArrayNotation = false)
{
if ($this->getValue('confirm') === '1') {
// use configuration
return $this->config;
}
return null;
}
}

View File

@ -0,0 +1,97 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Form\Setup;
use Icinga\Protocol\Dns;
use Icinga\Web\Form;
use Icinga\Web\Form\Element\Note;
use Icinga\Form\LdapDiscoveryForm;
use Icinga\Form\Config\Resource\LdapResourceForm;
use Icinga\Web\Request;
/**
* Wizard page to define the connection details for a LDAP resource
*/
class LdapDiscoveryPage extends Form
{
/**
* @var LdapDiscoveryForm
*/
private $discoveryForm;
/**
* Initialize this page
*/
public function init()
{
$this->setName('setup_ldap_discovery');
}
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
$this->addElement(
new Note(
'description',
array(
'value' => t(
'You can use this page to discover LDAP or ActiveDirectory servers ' .
' for authentication. If you don\' want to execute a discovery, just skip this step.'
)
)
)
);
$this->discoveryForm = new LdapDiscoveryForm();
$this->addElements($this->discoveryForm->createElements($formData)->getElements());
$this->addElement(
'checkbox',
'skip_validation',
array(
'required' => true,
'label' => t('Skip'),
'description' => t('Do not discover LDAP servers and enter all settings manually.')
)
);
}
/**
* Validate the given form data and check whether a BIND-request is successful
*
* @param array $data The data to validate
*
* @return bool
*/
public function isValid($data)
{
if ($data['skip_validation'] === '1') {
return true;
}
if (false === parent::isValid($data)) {
return false;
}
if (false === $this->discoveryForm->isValid($data)) {
return false;
}
return true;
}
public function getValues($suppressArrayNotation = false)
{
if (! isset($this->discoveryForm) || ! $this->discoveryForm->hasSuggestion()) {
return null;
}
return array(
'domain' => $this->getValue('domain'),
'type' => $this->discoveryForm->isAd() ?
LdapDiscoveryConfirmPage::TYPE_AD : LdapDiscoveryConfirmPage::TYPE_MISC,
'resource' => $this->discoveryForm->suggestResourceSettings(),
'backend' => $this->discoveryForm->suggestBackendSettings()
);
}
}

View File

@ -13,6 +13,13 @@ use Icinga\Form\Config\Resource\LdapResourceForm;
*/
class LdapResourcePage extends Form
{
/**
* Suggested configuration settings
*
* @var array
*/
protected $suggestions;
/**
* Initialize this page
*/
@ -21,6 +28,19 @@ class LdapResourcePage extends Form
$this->setName('setup_ldap_resource');
}
/**
* Set suggested configuration settings
*
* @param array $suggestions
*
* @return self
*/
public function setSuggestions(array $suggestions)
{
$this->suggestions = $suggestions;
return $this;
}
/**
* @see Form::createElements()
*/
@ -59,6 +79,10 @@ class LdapResourcePage extends Form
);
}
if ($this->suggestions !== null) {
$formData += $this->suggestions;
}
$resourceForm = new LdapResourceForm();
$this->addElements($resourceForm->createElements($formData)->getElements());
}

View File

@ -11,6 +11,8 @@ use Icinga\Form\Setup\DbResourcePage;
use Icinga\Form\Setup\PreferencesPage;
use Icinga\Form\Setup\AuthBackendPage;
use Icinga\Form\Setup\AdminAccountPage;
use Icinga\Form\Setup\LdapDiscoveryPage;
use Icinga\Form\Setup\LdapDiscoveryConfirmPage;
use Icinga\Form\Setup\LdapResourcePage;
use Icinga\Form\Setup\RequirementsPage;
use Icinga\Form\Setup\GeneralConfigPage;
@ -56,6 +58,8 @@ class WebSetup extends Wizard implements SetupWizard
$this->addPage(new AuthenticationPage());
$this->addPage(new PreferencesPage());
$this->addPage(new DbResourcePage());
$this->addPage(new LdapDiscoveryPage());
$this->addPage(new LdapDiscoveryConfirmPage());
$this->addPage(new LdapResourcePage());
$this->addPage(new AuthBackendPage());
$this->addPage(new AdminAccountPage());
@ -82,7 +86,15 @@ class WebSetup extends Wizard implements SetupWizard
$page->setResourceConfig($this->getPageData('setup_db_resource'));
} elseif ($authData['type'] === 'ldap') {
$page->setResourceConfig($this->getPageData('setup_ldap_resource'));
$suggestions = $this->getPageData('setup_ldap_discovery_confirm');
if (isset($suggestions['backend'])) {
$page->setSuggestions($suggestions['backend']);
}
}
} else if ($page->getName() === 'setup_ldap_discovery_confirm') {
$page->setResourceConfig($this->getPageData('setup_ldap_discovery'));
} elseif ($page->getName() === 'setup_admin_account') {
$page->setBackendConfig($this->getPageData('setup_authentication_backend'));
$authData = $this->getPageData('setup_authentication_type');
@ -108,6 +120,11 @@ class WebSetup extends Wizard implements SetupWizard
t('The given resource name must be unique and is already in use by the database resource')
);
}
$suggestion = $this->getPageData('setup_ldap_discovery_confirm');
if (isset($suggestion['resource'])) {
$page->setSuggestions($suggestion['resource']);
}
} elseif ($page->getName() === 'setup_authentication_type') {
$authData = $this->getPageData($page->getName());
if ($authData !== null && $request->getPost('type') !== $authData['type']) {
@ -131,6 +148,8 @@ class WebSetup extends Wizard implements SetupWizard
$prefData = $this->getPageData('setup_preferences_type');
$authData = $this->getPageData('setup_authentication_type');
$skip = $prefData['type'] !== 'db' && $authData['type'] !== 'db';
} elseif ($newPage->getName() === 'setup_ldap_discovery_confirm') {
$skip = $this->getPageData('setup_ldap_discovery') === null;
} elseif ($newPage->getName() === 'setup_ldap_resource') {
$authData = $this->getPageData('setup_authentication_type');
$skip = $authData['type'] !== 'ldap';