Skip to content

Commit

Permalink
Add LDAP discovery pages
Browse files Browse the repository at this point in the history
refs #7163
  • Loading branch information
majentsch authored and Johannes Meyer committed Oct 9, 2014
1 parent df69fd2 commit e29a568
Show file tree
Hide file tree
Showing 6 changed files with 506 additions and 0 deletions.
214 changes: 214 additions & 0 deletions application/forms/LdapDiscoveryForm.php
@@ -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);
}
}
24 changes: 24 additions & 0 deletions application/forms/Setup/AuthBackendPage.php
Expand Up @@ -23,6 +23,13 @@ class AuthBackendPage extends Form
*/
protected $config;

/**
* Suggested configuration settings
*
* @var array
*/
protected $suggestions;

/**
* Initialize this page
*/
Expand Down Expand Up @@ -54,6 +61,19 @@ public function getResourceConfig()
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()
*/
Expand Down Expand Up @@ -85,6 +105,10 @@ public function createElements(array $formData)
$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'
Expand Down
128 changes: 128 additions & 0 deletions application/forms/Setup/LdapDiscoveryConfirmPage.php
@@ -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;
}
}

0 comments on commit e29a568

Please sign in to comment.