Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 29 additions & 11 deletions src/Symfony/Component/Ldap/Adapter/AbstractConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,40 @@ abstract class AbstractConnection implements ConnectionInterface
public function __construct(array $config = array())
{
$resolver = new OptionsResolver();

$this->configureOptions($resolver);

$this->config = $resolver->resolve($config);
}

/**
* Configures the adapter's options.
*
* @param OptionsResolver $resolver An OptionsResolver instance
*/
protected function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'host' => null,
'port' => 389,
'host' => 'localhost',
'version' => 3,
'useSsl' => false,
'useStartTls' => false,
'optReferrals' => false,
'connection_string' => null,
'encryption' => 'none',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about 'secure' instead of encryption?

Copy link
Contributor Author

@csarrazi csarrazi May 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encryption having a value of none, tls or ssl, I think something like array('secure' => 'ssl') would make it misleading, as we are only talking about encryption over the wire, not neither authentication or RBAC.

'options' => array(),
));
$resolver->setNormalizer('host', function (Options $options, $value) {
if ($value && $options['useSsl']) {
return 'ldaps://'.$value;
}

return $value;
$resolver->setDefault('port', function (Options $options) {
return 'ssl' === $options['encryption'] ? 636 : 389;
});

$this->config = $resolver->resolve($config);
$resolver->setDefault('connection_string', function (Options $options) {
return sprintf('ldap%s://%s:%s', 'ssl' === $options['encryption'] ? 's' : '', $options['host'], $options['port']);
});

$resolver->setAllowedTypes('host', 'string');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take into account that OptionsResolver has fluent setters, which allows you to chain multiple calls.

$resolver->setAllowedTypes('port', 'numeric');
$resolver->setAllowedTypes('connection_string', 'string');
$resolver->setAllowedTypes('version', 'numeric');
$resolver->setAllowedValues('encryption', array('none', 'ssl', 'tls'));
$resolver->setAllowedTypes('options', 'array');
}
}
65 changes: 59 additions & 6 deletions src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Symfony\Component\Ldap\Adapter\AbstractConnection;
use Symfony\Component\Ldap\Exception\ConnectionException;
use Symfony\Component\Ldap\Exception\LdapException;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* @author Charles Sarrazin <charles@sarraz.in>
Expand Down Expand Up @@ -67,24 +69,75 @@ public function getResource()
return $this->connection;
}

public function setOption($name, $value)
{
if (!@ldap_set_option($this->connection, ConnectionOptions::getOption($name), $value)) {
throw new LdapException(sprintf('Could not set value "%s" for option "%s".', $value, $name));
}
}

public function getOption($name)
{
if (!@ldap_get_option($this->connection, ConnectionOptions::getOption($name), $ret)) {
throw new LdapException(sprintf('Could not retrieve value for option "%s".', $name));
}

return $ret;
}

protected function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);

$resolver->setDefault('debug', false);
$resolver->setAllowedTypes('debug', 'bool');
$resolver->setDefault('referrals', false);
$resolver->setAllowedTypes('referrals', 'bool');

$resolver->setNormalizer('options', function (Options $options, $value) {
if (true === $options['debug']) {
$value['debug_level'] = 7;
}

if (!isset($value['protocol_version'])) {
$value['protocol_version'] = $options['version'];
}

if (!isset($value['referrals'])) {
$value['referrals'] = $options['referrals'];
}

return $value;
});

$resolver->setAllowedValues('options', function (array $values) {
foreach ($values as $name => $value) {
if (!ConnectionOptions::isOption($name)) {
return false;
}
}

return true;
});
}

private function connect()
{
if ($this->connection) {
return;
}

$host = $this->config['host'];

ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->config['version']);
ldap_set_option($this->connection, LDAP_OPT_REFERRALS, $this->config['optReferrals']);
$this->connection = ldap_connect($this->config['connection_string']);

$this->connection = ldap_connect($host, $this->config['port']);
foreach ($this->config['options'] as $name => $value) {
$this->setOption($name, $value);
}

if (false === $this->connection) {
throw new LdapException(sprintf('Could not connect to Ldap server: %s', ldap_error($this->connection)));
}

if ($this->config['useStartTls'] && false === ldap_start_tls($this->connection)) {
if ('tls' === $this->config['encryption'] && false === ldap_start_tls($this->connection)) {
throw new LdapException(sprintf('Could not initiate TLS connection: %s', ldap_error($this->connection)));
}
}
Expand Down
78 changes: 78 additions & 0 deletions src/Symfony/Component/Ldap/Adapter/ExtLdap/ConnectionOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Ldap\Adapter\ExtLdap;

use Symfony\Component\Ldap\Exception\LdapException;

/**
* A class representing the Ldap extension's options, which can be used with
* ldap_set_option or ldap_get_option.
*
* @author Charles Sarrazin <charles@sarraz.in>
*
* @internal
*/
final class ConnectionOptions
{
const API_INFO = 0x00;
const DEREF = 0x02;
const SIZELIMIT = 0x03;
const TIMELIMIT = 0x04;
const REFERRALS = 0x08;
const RESTART = 0x09;
const PROTOCOL_VERSION = 0x11;
const SERVER_CONTROLS = 0x12;
const CLIENT_CONTROLS = 0x13;
const API_FEATURE_INFO = 0x15;
const HOST_NAME = 0x30;
const ERROR_NUMBER = 0x31;
const ERROR_STRING = 0x32;
const MATCHED_DN = 0x33;
const DEBUG_LEVEL = 0x5001;
const NETWORK_TIMEOUT = 0x5005;
const X_SASL_MECH = 0x6100;
const X_SASL_REALM = 0x6101;
const X_SASL_AUTHCID = 0x6102;
const X_SASL_AUTHZID = 0x6103;

public static function getOptionName($name)
{
return sprintf('%s::%s', self::class, strtoupper($name));
}

/**
* Fetches an option's corresponding constant value from an option name.
* The option name can either be in snake or camel case.
*
* @param string $name
*
* @return int
*
* @throws LdapException
*/
public static function getOption($name)
{
// Convert
$constantName = self::getOptionName($name);

if (!defined($constantName)) {
throw new LdapException(sprintf('Unknown option "%s"', $name));
}

return constant($constantName);
}

public static function isOption($name)
{
return defined(self::getOptionName($name));
}
}
4 changes: 2 additions & 2 deletions src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __destruct()
$con = $this->connection->getResource();
$this->connection = null;

if (null === $this->search) {
if (null === $this->search || false === $this->search) {
return;
}

Expand All @@ -60,7 +60,7 @@ public function execute()

$con = $this->connection->getResource();

$this->search = ldap_search(
$this->search = @ldap_search(
$con,
$this->dn,
$this->query,
Expand Down
11 changes: 4 additions & 7 deletions src/Symfony/Component/Ldap/Adapter/QueryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
* file that was distributed with this source code.
*/

/**
* @author Charles Sarrazin <charles@sarraz.in>
*/
namespace Symfony\Component\Ldap\Adapter;

use Symfony\Component\Ldap\Entry;
Expand All @@ -21,10 +18,10 @@
*/
interface QueryInterface
{
const DEREF_NEVER = 0;
const DEREF_SEARCHING = 1;
const DEREF_FINDING = 2;
const DEREF_ALWAYS = 3;
const DEREF_NEVER = 0x00;
const DEREF_SEARCHING = 0x01;
const DEREF_FINDING = 0x02;
const DEREF_ALWAYS = 0x03;

/**
* Executes a query and returns the list of Ldap entries.
Expand Down