parent
4a982a382e
commit
1b440a4f1b
|
@ -7,6 +7,7 @@ use Exception;
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
use Icinga\Data\ConfigObject;
|
use Icinga\Data\ConfigObject;
|
||||||
use Icinga\Data\ResourceFactory;
|
use Icinga\Data\ResourceFactory;
|
||||||
|
use Icinga\Protocol\Ldap\Connection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form class for adding/modifying ldap resources
|
* Form class for adding/modifying ldap resources
|
||||||
|
@ -57,6 +58,40 @@ class LdapResourceForm extends Form
|
||||||
'value' => 389
|
'value' => 389
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'connection',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'autosubmit' => true,
|
||||||
|
'label' => $this->translate('Connection'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The type of connection to use. Unencrypted (Plaintext) or encrypted (SSL, TLS).'
|
||||||
|
),
|
||||||
|
'multiOptions' => array(
|
||||||
|
'plaintext' => $this->translate('Plaintext'),
|
||||||
|
Connection::SSL => 'Secure Sockets Layer (SSL)',
|
||||||
|
Connection::STARTTLS => 'Transport Layer Security (TLS)'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($formData['connection']) && $formData['connection'] !== 'plaintext') {
|
||||||
|
// TODO(jom): Do not show this checkbox unless the connection is actually failing due to certificate errors
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'reqcert',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Require Certificate'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'When checked, the LDAP server must provide a valid and known (trusted) certificate.'
|
||||||
|
),
|
||||||
|
'value' => 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'text',
|
'text',
|
||||||
'root_dn',
|
'root_dn',
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
namespace Icinga\Protocol\Ldap;
|
namespace Icinga\Protocol\Ldap;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Protocol\Ldap\Exception as LdapException;
|
use Icinga\Protocol\Ldap\Exception as LdapException;
|
||||||
use Icinga\Application\Platform;
|
use Icinga\Application\Platform;
|
||||||
|
@ -35,6 +34,8 @@ class Connection
|
||||||
const LDAP_SIZELIMIT_EXCEEDED = 4;
|
const LDAP_SIZELIMIT_EXCEEDED = 4;
|
||||||
const LDAP_ADMINLIMIT_EXCEEDED = 11;
|
const LDAP_ADMINLIMIT_EXCEEDED = 11;
|
||||||
const PAGE_SIZE = 1000;
|
const PAGE_SIZE = 1000;
|
||||||
|
const STARTTLS = 'tls';
|
||||||
|
const SSL = 'ssl';
|
||||||
|
|
||||||
protected $ds;
|
protected $ds;
|
||||||
protected $hostname;
|
protected $hostname;
|
||||||
|
@ -43,6 +44,8 @@ class Connection
|
||||||
protected $bind_pw;
|
protected $bind_pw;
|
||||||
protected $root_dn;
|
protected $root_dn;
|
||||||
protected $count;
|
protected $count;
|
||||||
|
protected $connectionType;
|
||||||
|
protected $reqCert = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the bind on this connection was already performed
|
* Whether the bind on this connection was already performed
|
||||||
|
@ -66,8 +69,6 @@ class Connection
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* TODO: Allow to pass port and SSL options
|
|
||||||
*
|
|
||||||
* @param ConfigObject $config
|
* @param ConfigObject $config
|
||||||
*/
|
*/
|
||||||
public function __construct(ConfigObject $config)
|
public function __construct(ConfigObject $config)
|
||||||
|
@ -77,6 +78,8 @@ class Connection
|
||||||
$this->bind_pw = $config->bind_pw;
|
$this->bind_pw = $config->bind_pw;
|
||||||
$this->root_dn = $config->root_dn;
|
$this->root_dn = $config->root_dn;
|
||||||
$this->port = $config->get('port', $this->port);
|
$this->port = $config->get('port', $this->port);
|
||||||
|
$this->connectionType = $config->connection;
|
||||||
|
$this->reqCert = (bool) $config->get('reqcert', $this->reqCert);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHostname()
|
public function getHostname()
|
||||||
|
@ -470,59 +473,53 @@ class Connection
|
||||||
*/
|
*/
|
||||||
protected function prepareNewConnection()
|
protected function prepareNewConnection()
|
||||||
{
|
{
|
||||||
$use_tls = false;
|
if ($this->connectionType === static::STARTTLS || $this->connectionType === static::SSL) {
|
||||||
$force_tls = false;
|
|
||||||
|
|
||||||
if ($use_tls) {
|
|
||||||
$this->prepareTlsEnvironment();
|
$this->prepareTlsEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
$ds = ldap_connect($this->hostname, $this->port);
|
$hostname = $this->hostname;
|
||||||
|
if ($this->connectionType === static::SSL) {
|
||||||
|
$hostname = 'ldaps://' . $hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ds = ldap_connect($hostname, $this->port);
|
||||||
try {
|
try {
|
||||||
$this->capabilities = $this->discoverCapabilities($ds);
|
$this->capabilities = $this->discoverCapabilities($ds);
|
||||||
$this->discoverySuccess = true;
|
$this->discoverySuccess = true;
|
||||||
|
|
||||||
} catch (LdapException $e) {
|
} catch (LdapException $e) {
|
||||||
|
|
||||||
// create empty default capabilities
|
// create empty default capabilities
|
||||||
Logger::warning('LADP discovery failed, assuming default LDAP settings.');
|
Logger::warning('LADP discovery failed, assuming default LDAP settings.');
|
||||||
$this->capabilities = new Capability();
|
$this->capabilities = new Capability();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($use_tls) {
|
if ($this->connectionType === static::STARTTLS) {
|
||||||
|
$force_tls = false;
|
||||||
if ($this->capabilities->hasStartTLS()) {
|
if ($this->capabilities->hasStartTLS()) {
|
||||||
if (@ldap_start_tls($ds)) {
|
if (@ldap_start_tls($ds)) {
|
||||||
Logger::debug('LDAP STARTTLS succeeded');
|
Logger::debug('LDAP STARTTLS succeeded');
|
||||||
} else {
|
} else {
|
||||||
Logger::debug('LDAP STARTTLS failed: %s', ldap_error($ds));
|
Logger::error('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||||
throw new LdapException(
|
throw new LdapException('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||||
'LDAP STARTTLS failed: %s',
|
|
||||||
ldap_error($ds)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} elseif ($force_tls) {
|
} elseif ($force_tls) {
|
||||||
throw new LdapException(
|
throw new LdapException('STARTTLS is required but not announced by %s', $this->hostname);
|
||||||
'TLS is required but not announced by %s',
|
|
||||||
$this->hostname
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
Logger::warning('LDAP TLS enabled but not announced');
|
Logger::warning('LDAP STARTTLS enabled but not announced');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ldap_rename requires LDAPv3:
|
// ldap_rename requires LDAPv3:
|
||||||
if ($this->capabilities->hasLdapV3()) {
|
if ($this->capabilities->hasLdapV3()) {
|
||||||
if (! ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
|
if (! ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
|
||||||
throw new LdapException('LDAPv3 is required');
|
throw new LdapException('LDAPv3 is required');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// TODO: remove this -> FORCING v3 for now
|
// TODO: remove this -> FORCING v3 for now
|
||||||
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
|
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
Logger::warning('No LDAPv3 support detected');
|
Logger::warning('No LDAPv3 support detected');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not setting this results in "Operations error" on AD when using the
|
// Not setting this results in "Operations error" on AD when using the whole domain as search base
|
||||||
// whole domain as search base:
|
|
||||||
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
|
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
|
||||||
// ldap_set_option($ds, LDAP_OPT_DEREF, LDAP_DEREF_NEVER);
|
// ldap_set_option($ds, LDAP_OPT_DEREF, LDAP_DEREF_NEVER);
|
||||||
return $ds;
|
return $ds;
|
||||||
|
@ -530,17 +527,16 @@ class Connection
|
||||||
|
|
||||||
protected function prepareTlsEnvironment()
|
protected function prepareTlsEnvironment()
|
||||||
{
|
{
|
||||||
$strict_tls = true;
|
|
||||||
// TODO: allow variable known CA location (system VS Icinga)
|
// TODO: allow variable known CA location (system VS Icinga)
|
||||||
if (Platform::isWindows()) {
|
if (Platform::isWindows()) {
|
||||||
// putenv('LDAP...')
|
putenv('LDAPTLS_REQCERT=never');
|
||||||
} else {
|
} else {
|
||||||
if ($strict_tls) {
|
if ($this->reqCert) {
|
||||||
$ldap_conf = $this->getConfigDir('ldap_ca.conf');
|
$ldap_conf = $this->getConfigDir('ldap_ca.conf');
|
||||||
} else {
|
} else {
|
||||||
$ldap_conf = $this->getConfigDir('ldap_nocert.conf');
|
$ldap_conf = $this->getConfigDir('ldap_nocert.conf');
|
||||||
}
|
}
|
||||||
putenv('LDAPRC=' . $ldap_conf);
|
putenv('LDAPRC=' . $ldap_conf); // TODO: Does not have any effect
|
||||||
if (getenv('LDAPRC') !== $ldap_conf) {
|
if (getenv('LDAPRC') !== $ldap_conf) {
|
||||||
throw new LdapException('putenv failed');
|
throw new LdapException('putenv failed');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue