vendor/symfony/ldap/Adapter/ExtLdap/Connection.php line 75

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Ldap\Adapter\ExtLdap;
  11. use LDAP\Connection as LDAPConnection;
  12. use Symfony\Component\Ldap\Adapter\AbstractConnection;
  13. use Symfony\Component\Ldap\Exception\AlreadyExistsException;
  14. use Symfony\Component\Ldap\Exception\ConnectionException;
  15. use Symfony\Component\Ldap\Exception\ConnectionTimeoutException;
  16. use Symfony\Component\Ldap\Exception\InvalidCredentialsException;
  17. use Symfony\Component\Ldap\Exception\LdapException;
  18. use Symfony\Component\OptionsResolver\Options;
  19. use Symfony\Component\OptionsResolver\OptionsResolver;
  20. /**
  21.  * @author Charles Sarrazin <charles@sarraz.in>
  22.  */
  23. class Connection extends AbstractConnection
  24. {
  25.     private const LDAP_INVALID_CREDENTIALS 0x31;
  26.     private const LDAP_TIMEOUT 0x55;
  27.     private const LDAP_ALREADY_EXISTS 0x44;
  28.     private const PRECONNECT_OPTIONS = [
  29.         ConnectionOptions::DEBUG_LEVEL,
  30.         ConnectionOptions::X_TLS_CACERTDIR,
  31.         ConnectionOptions::X_TLS_CACERTFILE,
  32.         ConnectionOptions::X_TLS_REQUIRE_CERT,
  33.     ];
  34.     private bool $bound false;
  35.     /** @var resource|LDAPConnection */
  36.     private $connection;
  37.     public function __sleep(): array
  38.     {
  39.         throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
  40.     }
  41.     public function __wakeup()
  42.     {
  43.         throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
  44.     }
  45.     public function __destruct()
  46.     {
  47.         $this->disconnect();
  48.     }
  49.     public function isBound(): bool
  50.     {
  51.         return $this->bound;
  52.     }
  53.     /**
  54.      * @param string $password WARNING: When the LDAP server allows unauthenticated binds, a blank $password will always be valid
  55.      *
  56.      * @return void
  57.      */
  58.     public function bind(string $dn null, #[\SensitiveParameterstring $password null)
  59.     {
  60.         if (!$this->connection) {
  61.             $this->connect();
  62.         }
  63.         if (false === @ldap_bind($this->connection$dn$password)) {
  64.             $error ldap_error($this->connection);
  65.             switch (ldap_errno($this->connection)) {
  66.                 case self::LDAP_INVALID_CREDENTIALS:
  67.                     throw new InvalidCredentialsException($error);
  68.                 case self::LDAP_TIMEOUT:
  69.                     throw new ConnectionTimeoutException($error);
  70.                 case self::LDAP_ALREADY_EXISTS:
  71.                     throw new AlreadyExistsException($error);
  72.             }
  73.             throw new ConnectionException($error);
  74.         }
  75.         $this->bound true;
  76.     }
  77.     /**
  78.      * @return resource|LDAPConnection
  79.      *
  80.      * @internal
  81.      */
  82.     public function getResource()
  83.     {
  84.         return $this->connection;
  85.     }
  86.     /**
  87.      * @return void
  88.      */
  89.     public function setOption(string $name, array|string|int|bool $value)
  90.     {
  91.         if (!@ldap_set_option($this->connectionConnectionOptions::getOption($name), $value)) {
  92.             throw new LdapException(sprintf('Could not set value "%s" for option "%s".'$value$name));
  93.         }
  94.     }
  95.     /**
  96.      * @return array|string|int|null
  97.      */
  98.     public function getOption(string $name)
  99.     {
  100.         if (!@ldap_get_option($this->connectionConnectionOptions::getOption($name), $ret)) {
  101.             throw new LdapException(sprintf('Could not retrieve value for option "%s".'$name));
  102.         }
  103.         return $ret;
  104.     }
  105.     /**
  106.      * @return void
  107.      */
  108.     protected function configureOptions(OptionsResolver $resolver)
  109.     {
  110.         parent::configureOptions($resolver);
  111.         $resolver->setDefault('debug'false);
  112.         $resolver->setAllowedTypes('debug''bool');
  113.         $resolver->setDefault('referrals'false);
  114.         $resolver->setAllowedTypes('referrals''bool');
  115.         $resolver->setDefault('options', function (OptionsResolver $optionsOptions $parent) {
  116.             $options->setDefined(array_map('strtolower'array_keys((new \ReflectionClass(ConnectionOptions::class))->getConstants())));
  117.             if (true === $parent['debug']) {
  118.                 $options->setDefault('debug_level'7);
  119.             }
  120.             if (!isset($parent['network_timeout'])) {
  121.                 $options->setDefault('network_timeout'\ini_get('default_socket_timeout'));
  122.             }
  123.             $options->setDefaults([
  124.                 'protocol_version' => $parent['version'],
  125.                 'referrals' => $parent['referrals'],
  126.             ]);
  127.         });
  128.     }
  129.     private function connect(): void
  130.     {
  131.         if ($this->connection) {
  132.             return;
  133.         }
  134.         foreach ($this->config['options'] as $name => $value) {
  135.             if (\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONStrue)) {
  136.                 $this->setOption($name$value);
  137.             }
  138.         }
  139.         if (false === $connection ldap_connect($this->config['connection_string'])) {
  140.             throw new LdapException('Invalid connection string: '.$this->config['connection_string']);
  141.         } else {
  142.             $this->connection $connection;
  143.         }
  144.         foreach ($this->config['options'] as $name => $value) {
  145.             if (!\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONStrue)) {
  146.                 $this->setOption($name$value);
  147.             }
  148.         }
  149.         if ('tls' === $this->config['encryption'] && false === @ldap_start_tls($this->connection)) {
  150.             throw new LdapException('Could not initiate TLS connection: '.ldap_error($this->connection));
  151.         }
  152.     }
  153.     private function disconnect(): void
  154.     {
  155.         if ($this->connection) {
  156.             ldap_unbind($this->connection);
  157.         }
  158.         $this->connection null;
  159.         $this->bound false;
  160.     }
  161. }