Commit bfec55f1 authored by stanislav.goldmann's avatar stanislav.goldmann

Support for backup rebinds

parent 4d1112b7
......@@ -13,7 +13,7 @@ Add to your root composer.json and install with `composer install` or `composer
{
require: {
"krenor/ldap-auth": "~1.0"
"krenor/ldap-auth": "~1.1"
}
}
......@@ -48,18 +48,26 @@ It should look like this.
return [
'suffix' => '@example.local',
'domain_controller' => 'dns.example.local',
'domain_controller' => ['dns2.example.local', 'dns1.example.local],
'base_dn' => 'OU=People,DC=example,DC=local',
'ssl' => false, // if using TLS this MUST be false
'tls' => false, // // if using SSL this MUST be false
'admin_user' => 'admin', // Prevent anonymous bindings
'admin_pass' => 'admin' // Prevent anonymous bindings
// Indicates to use the hostnames sequentially. This means that this package
// will try dns2.example.local first. If it's down, it tries the next one
// If this is set to false, load balancing will be used instead (random domain controller)
'backup_rebind' => true,
// if using TLS this MUST be false
'ssl' => false,
// if using SSL this MUST be false
'tls' => false,
// Prevent anonymous bindings
'admin_user' => 'admin',
// Prevent anonymous bindings
'admin_pass' => 'admin'
];
```
You may use an array of Domain Controllers instead of a single one.
You may use a single domain controller or multiple ones. Enter them as array, not as string!
```php
'domain_controller' => ['dns1.example.local', 'dns2.example.local']
'domain_controller' => ['dns1.example.local']
```
## Usage
......
......@@ -8,6 +8,23 @@ use Krenor\LdapAuth\Exceptions\ConnectionException;
class LdapConnection implements ConnectionInterface
{
/**
* Array of domain controller(s) to balance LDAP queries
*
* @var array
*/
protected $domainController = [ ];
/**
* Indicates whether or not to use the array of domain controller sequentially
* So on downtime of a server it checks if the next one can be reached.
* If this is set to false load balancing is used instead for multiple dc's
*
* @var bool
*/
protected $useBackup = false;
/**
* Indicates whether or not to use SSL
*
......@@ -36,6 +53,7 @@ class LdapConnection implements ConnectionInterface
*/
protected $bound = false;
/**
* Constructor
*
......@@ -43,25 +61,35 @@ class LdapConnection implements ConnectionInterface
*/
public function __construct(array $config)
{
if($config['tls']) $this->tls = true;
if($config['ssl']) $this->ssl = true;
$this->domainController = $config['domain_controller'];
if ($config['tls']) {
$this->tls = true;
}
if ($config['ssl']) {
$this->ssl = true;
}
if ($config['backup_rebind']) {
$this->useBackup = true;
}
}
/**
* Initialises a Connection via hostname
*
* @param string $hostname
*
* @return resource
*/
public function connect($hostname)
public function connect()
{
$protocol = $this->ssl ? $this::PROTOCOL_SSL : $this::PROTOCOL;
$port = $this->ssl ? $this::PORT_SSL : $this::PORT;
return $this->connection = ldap_connect($protocol . $hostname, $port);
$hostname = $this->chooseDomainController();
return $this->connection = ldap_connect($hostname, $port);
}
/**
* Binds LDAP connection to the server
*
......@@ -75,25 +103,60 @@ class LdapConnection implements ConnectionInterface
public function bind($username, $password)
{
// Tries to run the LDAP Connection as TLS
if($this->tls){
if(!ldap_start_tls($this->connection)){
if ($this->tls) {
if ( ! ldap_start_tls($this->connection)) {
throw new ConnectionException('Unable to Connect to LDAP using TLS.');
}
}
try{
try {
$this->bound = ldap_bind($this->connection, $username, $password);
}
catch(ErrorException $e){
} catch (ErrorException $e) {
$this->bound = false;
}
return $this->bound;
}
/**
* Chooses based on the configuration which domain controller to connect to
*
* @return string
*/
private function chooseDomainController()
{
$protocol = $this->ssl ? $this::PROTOCOL_SSL : $this::PROTOCOL;
$count = count($this->domainController);
if ($count === 1) {
// Single domain controller, so use this one
return $protocol . $this->domainController[0];
}
if ($this->useBackup === true) {
$connectionString = null;
foreach ($this->domainController as $dc) {
$connectionString .= $protocol . $dc . ' ';
}
// In case of using backup_rebind we have to build a string of all
// domain controller which will be walked through sequentially
return $connectionString;
}
$loadBalancedDC = $this->domainController[array_rand($this->domainController)];
// Otherwise use "load balancing" by using a random domain controller
return $protocol . $loadBalancedDC;
}
/**
* @param $option
* @param $value
*
* @return bool
*/
public function option($option, $value)
......@@ -101,6 +164,7 @@ class LdapConnection implements ConnectionInterface
return ldap_set_option($this->connection, $option, $value);
}
/**
* @return string
*/
......@@ -109,10 +173,12 @@ class LdapConnection implements ConnectionInterface
return ldap_error($this->connection);
}
/**
* @param string $dn
* @param string $filter
* @param array $fields
* @param array $fields
*
* @return resource
*/
public function search($dn, $filter, array $fields)
......@@ -120,8 +186,10 @@ class LdapConnection implements ConnectionInterface
return ldap_search($this->connection, $dn, $filter, $fields);
}
/**
* @param $result
*
* @return array
*/
public function entry($result)
......@@ -129,6 +197,7 @@ class LdapConnection implements ConnectionInterface
return ldap_get_entries($this->connection, $result);
}
/**
* @return bool
*/
......@@ -137,6 +206,7 @@ class LdapConnection implements ConnectionInterface
return $this->bound;
}
/**
* @return bool
*/
......@@ -145,6 +215,7 @@ class LdapConnection implements ConnectionInterface
return $this->ssl;
}
/**
* @return bool
*/
......@@ -153,6 +224,7 @@ class LdapConnection implements ConnectionInterface
return $this->tls;
}
/**
* @return resource
*/
......
......@@ -42,18 +42,23 @@ interface ConnectionInterface
/**
* Whether to automatically follow referrals returned by the LDAP server
*
* @var boolean
* @var integer
*/
const REFERRALS = false;
const REFERRALS = 0;
/**
* Connects the specified hostname to the LDAP server
* Defines the time-out limit for connecting and binding in seconds
*
* @param string $hostname
* @var integer
*/
const TIMELIMIT = 6;
/**
* Connects the specified hostname to the LDAP server
*
* @return resource
*/
public function connect($hostname);
public function connect();
/**
* Binds the LDAP connection to the server with login credentials
......
......@@ -22,13 +22,6 @@ class Ldap {
*/
protected $base_dn;
/**
* Array of domain controller(s) to balance LDAP queries
*
* @var array
*/
protected $domain_controller = [];
/**
* If no anonymous login is allowed
*
......@@ -92,11 +85,15 @@ class Ldap {
*/
protected function connect(ConnectionInterface $connection)
{
$dc = is_array($this->domain_controller) ? array_rand($this->domain_controller) : $this->domain_controller;
$this->ldap->connect($dc);
$this->ldap->connect();
$this->ldap->option(LDAP_OPT_PROTOCOL_VERSION, $connection::PROTOCOL);
$this->ldap->option(LDAP_OPT_REFERRALS, $connection::REFERRALS);
$this->ldap->option(LDAP_OPT_TIMELIMIT, $connection::TIMELIMIT);
$this->ldap->option(LDAP_OPT_NETWORK_TIMEOUT, $connection::TIMELIMIT);
// For debug purposes only!
// $this->ldap->option(LDAP_OPT_DEBUG_LEVEL, 7);
$this->ldap->bind($this->admin_user, $this->admin_pass);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment