8000 [Ldap] Add LDAP error codes to exceptions #28677 · symfony/symfony@f8ccd48 · GitHub
[go: up one dir, main page]

Skip to content

Commit f8ccd48

Browse files
author
Dominic Tubach
committed
[Ldap] Add LDAP error codes to exceptions #28677
This PR ensures that an LdapException is only used when an LDAP operations fails. In cases an LdapException was used for non LDAP operations it is replaced by an appropriate exception.
1 parent 0890970 commit f8ccd48

16 files changed

+165
-57
lines changed

src/Symfony/Component/Ldap/Adapter/ExtLdap/Adapter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
1313

1414
use Symfony\Component\Ldap\Adapter\AdapterInterface;
15-
use Symfony\Component\Ldap\Exception\LdapException;
15+
use Symfony\Component\Ldap\Exception\ExtensionNotLoadedException;
1616

1717
/**
1818
* @author Charles Sarrazin <charles@sarraz.in>
@@ -26,7 +26,7 @@ class Adapter implements AdapterInterface
2626
public function __construct(array $config = [])
2727
{
2828
if (!\extension_loaded('ldap')) {
29-
throw new LdapException('The LDAP PHP extension is not enabled.');
29+
throw new ExtensionNotLoadedException('The LDAP PHP extension is not enabled.');
3030
}
3131

3232
$this->config = $config;

src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ public function count()
5151
$searches = $this->search->getResources();
5252
$count = 0;
5353
foreach ($searches as $search) {
54-
$searchCount = ldap_count_entries($con, $search);
54+
$searchCount = @ldap_count_entries($con, $search);
5555
if (false === $searchCount) {
56-
throw new LdapException(sprintf('Error while retrieving entry count: %s.', ldap_error($con)));
56+
throw LdapException::create('Error while retrieving entry count: [{errorCode}] {errorMsg}.', ldap_errno($con));
5757
}
5858
$count += $searchCount;
5959
}
@@ -73,10 +73,10 @@ public function getIterator()
7373
$con = $this->connection->getResource();
7474
$searches = $this->search->getResources();
7575
foreach ($searches as $search) {
76-
$current = ldap_first_entry($con, $search);
76+
$current = @ldap_first_entry($con, $search);
7777

7878
if (false === $current) {
79-
throw new LdapException(sprintf('Could not rewind entries array: %s.', ldap_error($con)));
79+
throw LdapException::create('Could not rewind entries array: [{errorCode}] {errorMsg}.', ldap_errno($con));
8080
}
8181

8282
yield $this->getSingleEntry($con, $current);
@@ -120,18 +120,18 @@ public function offsetUnset($offset)
120120

121121
private function getSingleEntry($con, $current)
122122
{
123-
$attributes = ldap_get_attributes($con, $current);
123+
$attributes = @ldap_get_attributes($con, $current);
124124

125125
if (false === $attributes) {
126-
throw new LdapException(sprintf('Could not fetch attributes: %s.', ldap_error($con)));
126+
throw LdapException::create('Could not fetch attributes: [{errorCode}] {errorMsg}.', ldap_errno($con));
127127
}
128128

129129
$attributes = $this->cleanupAttributes($attributes);
130130

131-
$dn = ldap_get_dn($con, $current);
131+
$dn = @ldap_get_dn($con, $current);
132132

133133
if (false === $dn) {
134-
throw new LdapException(sprintf('Could not fetch DN: %s.', ldap_error($con)));
134+
throw LdapException::create('Could not fetch DN: [{errorCode}] {errorMsg}.', ldap_errno($con));
135135
}
136136

137137
return new Entry($dn, $attributes);

src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,16 @@ public function bind($dn = null, $password = null)
5858
}
5959

6060
if (false === @ldap_bind($this->connection, $dn, $password)) {
61-
$error = ldap_error($this->connection);
62-
switch (ldap_errno($this->connection)) {
61+
$errorCode = ldap_errno($this->connection);
62+
switch ($errorCode) {
6363
case self::LDAP_INVALID_CREDENTIALS:
64-
throw new InvalidCredentialsException($error);
64+
throw InvalidCredentialsException::create('{errorMsg}', $errorCode);
6565
case self::LDAP_TIMEOUT:
66-
throw new ConnectionTimeoutException($error);
66+
throw ConnectionTimeoutException::create('{errorMsg}', $errorCode);
6767
case self::LDAP_ALREADY_EXISTS:
68-
throw new AlreadyExistsException($error);
68+
throw AlreadyExistsException::create('{errorMsg}', $errorCode);
6969
}
70-
throw new ConnectionException($error);
70+
throw ConnectionException::create('{errorMsg}', $errorCode);
7171
}
7272

7373
$this->bound = true;
@@ -88,14 +88,14 @@ public function getResource()
8888
public function setOption($name, $value)
8989
{
9090
if (!@ldap_set_option($this->connection, ConnectionOptions::getOption($name), $value)) {
91-
throw new LdapException(sprintf('Could not set value "%s" for option "%s".', $value, $name));
91+
throw LdapException::create(sprintf('Could not set value "%s" for option "%s": [{errorCode}] {errorMsg}.', $value, $name), ldap_errno($this->connection));
9292
}
9393
}
9494

9595
public function getOption($name)
9696
{
9797
if (!@ldap_get_option($this->connection, ConnectionOptions::getOption($name), $ret)) {
98-
throw new LdapException(sprintf('Could not retrieve value for option "%s".', $name));
98+
throw LdapException::create(sprintf('Could not retrieve value for option "%s": [{errorCode}] {errorMsg}.', $name), ldap_errno($this->connection));
9999
}
100100

101101
return $ret;
@@ -135,19 +135,17 @@ private function connect()
135135
$this->setOption($name, $value);
136136
}
137137

138-
if (false === $this->connection) {
139-
throw new LdapException(sprintf('Could not connect to Ldap server: %s.', ldap_error($this->connection)));
140-
}
141-
142138
if ('tls' === $this->config['encryption'] && false === @ldap_start_tls($this->connection)) {
143-
throw new LdapException(sprintf('Could not initiate TLS connection: %s.', ldap_error($this->connection)));
139+
throw LdapException::create('Could not initiate TLS connection: [{errorCode}] {errorMsg}.', ldap_errno($this->connection));
144140
}
145141
}
146142

147143
private function disconnect()
148144
{
149145
if ($this->connection && \is_resource($this->connection)) {
150-
ldap_unbind($this->connection);
146+
if (!@ldap_unbind($this->connection)) {
147+
throw LdapException::create('Could not unbind from LDAP: [{errorCode}] {errorMsg}', ldap_errno($this->connection));
148+
}
151149
}
152150

153151
$this->connection = null;

src/Symfony/Component/Ldap/Adapter/ExtLdap/ConnectionOptions.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
1313

14-
use Symfony\Component\Ldap\Exception\LdapException;
14+
use Symfony\Component\Ldap\Exception\UnexpectedValueException;
1515

1616
/**
1717
* A class representing the Ldap extension's options, which can be used with
@@ -73,15 +73,15 @@ public static function getOptionName($name)
7373
*
7474
* @param string $name
7575
*
76-
* @throws LdapException
76+
* @throws UnexpectedValueException
7777
*/
7878
public static function getOption($name): int
7979
{
8080
// Convert
8181
$constantName = self::getOptionName($name);
8282

8383
if (!\defined($constantName)) {
84-
throw new LdapException(sprintf('Unknown option "%s".', $name));
84+
throw new UnexpectedValueException(sprintf('Unknown option "%s".', $name));
8585
}
8686

8787
return \constant($constantName);

src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Ldap\Adapter\EntryManagerInterface;
1515
use Symfony\Component\Ldap\Entry;
1616
use Symfony\Component\Ldap\Exception\LdapException;
17+
use Symfony\Component\Ldap\Exception\MalformedDistinguishedNameException;
1718
use Symfony\Component\Ldap\Exception\NotBoundException;
1819
use Symfony\Component\Ldap\Exception\UpdateOperationException;
1920

@@ -38,7 +39,7 @@ public function add(Entry $entry)
3839
$con = $this->getConnectionResource();
3940

4041
if (!@ldap_add($con, $entry->getDn(), $entry->getAttributes())) {
41-
throw new LdapException(sprintf('Could not add entry "%s": %s.', $entry->getDn(), ldap_error($con)));
42+
throw LdapException::create(sprintf('Could not add entry "%s": [{errorCode}] {errorMsg}.', $entry->getDn()), ldap_errno($con));
4243
}
4344

4445
return $this;
@@ -52,7 +53,7 @@ public function update(Entry $entry)
5253
$con = $this->getConnectionResource();
5354

5455
if (!@ldap_modify($con, $entry->getDn(), $entry->getAttributes())) {
55-
throw new LdapException(sprintf('Could not update entry "%s": %s.', $entry->getDn(), ldap_error($con)));
56+
throw LdapException::create(sprintf('Could not update entry "%s": [{errorCode}] {errorMsg}.', $entry->getDn()), ldap_errno($con));
5657
}
5758
}
5859

@@ -64,7 +65,7 @@ public function remove(Entry $entry)
6465
$con = $this->getConnectionResource();
6566

6667
if (!@ldap_delete($con, $entry->getDn())) {
67-
throw new LdapException(sprintf('Could not remove entry "%s": %s.', $entry->getDn(), ldap_error($con)));
68+
throw LdapException::create(sprintf('Could not remove entry "%s": [{errorCode}] {errorMsg}.', $entry->getDn()), ldap_errno($con));
6869
}
6970
}
7071

@@ -79,7 +80,7 @@ public function addAttributeValues(Entry $entry, string $attribute, array $value
7980
$con = $this->getConnectionResource();
8081

8182
if (!@ldap_mod_add($con, $entry->getDn(), [$attribute => $values])) {
82-
throw new LdapException(sprintf('Could not add values to entry "%s", attribute %s: %s.', $entry->getDn(), $attribute, ldap_error($con)));
83+
throw LdapException::create(sprintf('Could not add values to entry "%s", attribute "%s": [{errorCode}] {errorMsg}.', $entry->getDn(), $attribute), ldap_errno($con));
8384
}
8485
}
8586

@@ -94,7 +95,7 @@ public function removeAttributeValues(Entry $entry, string $attribute, array $va
9495
$con = $this->getConnectionResource();
9596

9697
if (!@ldap_mod_del($con, $entry->getDn(), [$attribute => $values])) {
97-
throw new LdapException(sprintf('Could not remove values from entry "%s", attribute %s: %s.', $entry->getDn(), $attribute, ldap_error($con)));
98+
throw LdapException::create(sprintf('Could not remove values from entry "%s", attribute "%s": [{errorCode}] {errorMsg}.', $entry->getDn(), $attribute), ldap_errno($con));
9899
}
99100
}
100101

@@ -106,23 +107,24 @@ public function rename(Entry $entry, $newRdn, $removeOldRdn = true)
106107
$con = $this->getConnectionResource();
107108

108109
if (!@ldap_rename($con, $entry->getDn(), $newRdn, null, $removeOldRdn)) {
109-
throw new LdapException(sprintf('Could not rename entry "%s" to "%s": %s.', $entry->getDn(), $newRdn, ldap_error($con)));
110+
throw LdapException::create(sprintf('Could not rename entry "%s" to "%s": [{errorCode}] {errorMsg}.', $entry->getDn(), $newRdn), ldap_errno($con));
110111
}
111112
}
112113

113114
/**
114115
* Moves an entry on the Ldap server.
115116
*
116-
* @throws NotBoundException if the connection has not been previously bound
117-
* @throws LdapException if an error is thrown during the rename operation
117+
* @throws NotBoundException if the connection has not been previously bound
118+
* @throws LdapException if an error is thrown during the rename operation
119+
* @throws MalformedDistinguishedNameException if entry contains a malformed DN.
118120
*/
119121
public function move(Entry $entry, string $newParent)
120122
{
121123
$con = $this->getConnectionResource();
122124
$rdn = $this->parseRdnFromEntry($entry);
123125
// deleteOldRdn does not matter here, since the Rdn will not be changing in the move.
124126
if (!@ldap_rename($con, $entry->getDn(), $rdn, $newParent, true)) {
125-
throw new LdapException(sprintf('Could not move entry "%s" to "%s": %s.', $entry->getDn(), $newParent, ldap_error($con)));
127+
throw LdapException::create(sprintf('Could not move entry "%s" to "%s": [{errorCode}] {errorMsg}.', $entry->getDn(), $newParent), ldap_errno($con));
126128
}
127129
}
128130

@@ -152,14 +154,14 @@ public function applyOperations(string $dn, iterable $operations): void
152154
}
153155

154156
if (!@ldap_modify_batch($this->getConnectionResource(), $dn, $operationsMapped)) {
155-
throw new UpdateOperationException(sprintf('Error executing UpdateOperation on "%s": "%s".', $dn, ldap_error($this->getConnectionResource())));
157+
throw UpdateOperationException::create(sprintf('Error executing UpdateOperation on "%s": [{errorCode}] {errorMsg}.', $dn), ldap_errno($this->getConnectionResource()));
156158
}
157159
}
158160

159161
private function parseRdnFromEntry(Entry $entry)
160162
{
161163
if (!preg_match('/^([^,]+),/', $entry->getDn(), $matches)) {
162-
throw new LdapException(sprintf('Entry "%s" malformed, could not parse RDN.', $entry->getDn()));
164+
throw new MalformedDistinguishedNameException(sprintf('Entry "%s" malformed, could not parse RDN.', $entry->getDn()));
163165
}
164166

165167
return $matches[1];

src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
1313

1414
use Symfony\Component\Ldap\Adapter\AbstractQuery;
15+
use Symfony\Component\Ldap\Exception\DomainException;
1516
use Symfony\Component\Ldap\Exception\LdapException;
1617
use Symfony\Component\Ldap\Exception\NotBoundException;
1718

@@ -48,8 +49,8 @@ public function __destruct()
4849
if (false === $result || null === $result) {
4950
continue;
5051
}
51-
if (!ldap_free_result($result)) {
52-
throw new LdapException(sprintf('Could not free results: %s.', ldap_error($con)));
52+
if (!@ldap_free_result($result)) {
53+
throw LdapException::create('Could not free results: [{errorCode}] {errorMsg}.', ldap_errno($con));
5354
}
5455
}
5556
$this->results = null;
@@ -80,7 +81,7 @@ public function execute()
8081
$func = 'ldap_search';
8182
break;
8283
default:
83-
throw new LdapException(sprintf('Could not search in scope "%s".', $this->options['scope']));
84+
throw new DomainException(sprintf('Could not search in scope "%s".', $this->options['scope']));
8485
}
8586

8687
$itemsLeft = $maxItems = $this->options['maxItems'];
@@ -97,7 +98,9 @@ public function execute()
9798
$cookie = '';
9899
do {
99100
if ($pageControl) {
100-
ldap_control_paged_result($con, $pageSize, true, $cookie);
101+
if (!@ldap_control_paged_result($con, $pageSize, true, $cookie)) {
102+
throw LdapException::create('Could not send the LDAP pagination control: [{errorCode}] {errorMsg}.', ldap_errno($con));
103+
}
101104
}
102105
$sizeLimit = $itemsLeft;
103106
if ($pageSize > 0 && $sizeLimit >= $pageSize) {
@@ -115,15 +118,12 @@ public function execute()
115118
);
116119

117120
if (false === $search) {
118-
$ldapError = '';
119-
if ($errno = ldap_errno($con)) {
120-
$ldapError = sprintf(' LDAP error was [%d] %s', $errno, ldap_error($con));
121-
}
121+
$errorCode = ldap_errno($con);
122122
if ($pageControl) {
123123
$this->resetPagination();
124124
}
125125

126-
throw new LdapException(sprintf('Could not complete search with dn "%s", query "%s" and filters "%s".%s', $this->dn, $this->query, implode(',', $this->options['filter']), $ldapError));
126+
throw LdapException::create(sprintf('Could not complete search with dn "%s", query "%s" and filters "%s": [{errorCode}] {errorMsg}.', $this->dn, $this->query, implode(',', $this->options['filter'])), $errorCode);
127127
}
128128

129129
$this->results[] = $search;
@@ -133,7 +133,9 @@ public function execute()
133133
break;
134134
}
135135
if ($pageControl) {
136-
ldap_control_paged_result_response($con, $search, $cookie);
136+
if (!@ldap_control_paged_result_response($con, $search, $cookie)) {
137+
throw LdapException::create('Could not retrieve the LDAP pagination cookie: [{errorCode}] {errorMsg}.', ldap_errno($con));
138+
}
137139
}
138140
} while (null !== $cookie && '' !== $cookie);
139141

src/Symfony/Component/Ldap/Adapter/ExtLdap/UpdateOperation.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
1313

14-
use Symfony\Component\Ldap\Exception\UpdateOperationException;
14+
use Symfony\Component\Ldap\Exception\UnexpectedValueException;
1515

1616
class UpdateOperation
1717
{
@@ -30,15 +30,15 @@ class UpdateOperation
3030
* @param int $operationType An LDAP_MODIFY_BATCH_* constant
3131
* @param string $attribute The attribute to batch modify on
3232
*
33-
* @throws UpdateOperationException on consistency errors during construction
33+
* @throws UnexpectedValueException on consistency errors during construction
3434
*/
3535
public function __construct(int $operationType, string $attribute, ?array $values)
3636
{
3737
if (!\in_array($operationType, $this->validOperationTypes, true)) {
38-
throw new UpdateOperationException(sprintf('"%s" is not a valid modification type.', $operationType));
38+
throw new UnexpectedValueException(sprintf('"%s" is not a valid modification type.', $operationType));
3939
}
4040
if (LDAP_MODIFY_BATCH_REMOVE_ALL === $operationType && null !== $values) {
41-
throw new UpdateOperationException(sprintf('$values must be null for LDAP_MODIFY_BATCH_REMOVE_ALL operation, "%s" given.', \gettype($values)));
41+
throw new UnexpectedValueException(sprintf('$values must be null for LDAP_MODIFY_BATCH_REMOVE_ALL operation, "%s" given.', \gettype($values)));
4242
}
4343

4444
$this->operationType = $operationType;

src/Symfony/Component/Ldap/Exception/ConnectionException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
*
1717
* @author Grégoire Pineau <lyrixx@lyrixx.info>
1818
*/
19-
class ConnectionException extends \RuntimeException implements ExceptionInterface
19+
class ConnectionException extends LdapException implements ExceptionInterface
2020
{
2121
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Ldap\Exception;
13+
14+
class DomainException extends \DomainException implements ExceptionInterface
15+
{
16+
}

src/Symfony/Component/Ldap/Exception/DriverNotFoundException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\Component\Ldap\Exception;
1313

1414
/**
15-
* LdapException is thrown if php ldap module is not loaded.
15+
* DriverNotFoundException is thrown if adapter is not found in adapter map.
1616
*
1717
* @author Charles Sarrazin <charles@sarraz.in>
1818
*/

0 commit comments

Comments
 (0)
0