|
<?php |
|
|
|
namespace Kanboard\Core\Ldap; |
|
|
|
use LogicException; |
|
use Psr\Log\LoggerInterface; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Client |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $ldap; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private $logger; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function connect($username = null, $password = null) |
|
{ |
|
$client = new static; |
|
$client->open($client->getLdapServer()); |
|
$username = $username ?: $client->getLdapUsername(); |
|
$password = $password ?: $client->getLdapPassword(); |
|
|
|
if (empty($username) && empty($password)) { |
|
$client->useAnonymousAuthentication(); |
|
} else { |
|
$client->authenticate($username, $password); |
|
} |
|
|
|
return $client; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getConnection() |
|
{ |
|
return $this->ldap; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function open($server, $port = LDAP_PORT, $tls = LDAP_START_TLS, $verify = LDAP_SSL_VERIFY) |
|
{ |
|
if (! function_exists('ldap_connect')) { |
|
throw new ClientException('LDAP: The PHP LDAP extension is required'); |
|
} |
|
|
|
if (! $verify) { |
|
putenv('LDAPTLS_REQCERT=never'); |
|
} |
|
|
|
if (filter_var($server, FILTER_VALIDATE_URL) !== false) { |
|
$this->ldap = @ldap_connect($server); |
|
} |
|
else { |
|
$this->ldap = @ldap_connect($server, $port); |
|
} |
|
|
|
if ($this->ldap === false) { |
|
throw new ConnectionException('Malformed LDAP server hostname or LDAP server port'); |
|
} |
|
|
|
ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION, 3); |
|
ldap_set_option($this->ldap, LDAP_OPT_REFERRALS, 0); |
|
ldap_set_option($this->ldap, LDAP_OPT_NETWORK_TIMEOUT, 1); |
|
ldap_set_option($this->ldap, LDAP_OPT_TIMELIMIT, 1); |
|
|
|
if ($tls && ! @ldap_start_tls($this->ldap)) { |
|
throw new ConnectionException('Unable to start LDAP TLS (' . $this->getLdapError() . ')'); |
|
} |
|
|
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function useAnonymousAuthentication() |
|
{ |
|
if (! @ldap_bind($this->ldap)) { |
|
$this->checkForServerConnectionError(); |
|
throw new ClientException('Unable to perform anonymous binding => '.$this->getLdapError()); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function authenticate($bind_rdn, $bind_password) |
|
{ |
|
if (! @ldap_bind($this->ldap, $bind_rdn, $bind_password)) { |
|
$this->checkForServerConnectionError(); |
|
throw new ClientException('LDAP authentication failure for "'.$bind_rdn.'" => '.$this->getLdapError()); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getLdapServer() |
|
{ |
|
if (! LDAP_SERVER) { |
|
throw new LogicException('LDAP server not configured, check the parameter LDAP_SERVER'); |
|
} |
|
|
|
return LDAP_SERVER; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getLdapUsername() |
|
{ |
|
return LDAP_USERNAME; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getLdapPassword() |
|
{ |
|
return LDAP_PASSWORD; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function setLogger(LoggerInterface $logger) |
|
{ |
|
$this->logger = $logger; |
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getLogger() |
|
{ |
|
return $this->logger; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function hasLogger() |
|
{ |
|
return $this->logger !== null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function checkForServerConnectionError() |
|
{ |
|
if (ldap_errno($this->ldap) === -1) { |
|
throw new ConnectionException('Unable to connect to LDAP server (' . $this->getLdapError() . ')'); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function getLdapError() |
|
{ |
|
ldap_get_option($this->ldap, LDAP_OPT_ERROR_STRING, $extendedErrorMessage); |
|
$errorMessage = ldap_error($this->ldap); |
|
$errorCode = ldap_errno($this->ldap); |
|
|
|
return 'Code="'.$errorCode.'"; Error="'.$errorMessage.'"; ExtendedError="'.$extendedErrorMessage.'"'; |
|
} |
|
} |
|
|