Skip to content

Commit 56cd9c6

Browse files
committed
If an error occurs during a search and an operation exception is thrown, return the result code as part of the SearchResultDone message. This is how LDAP clients would expect it and how the RFC specifies that it would be done.
Currently, the operation exception comes as an unexpected message after the SearchResultDone which would be considered an unsolicited message from a clients perspective and would cause an immediate disconnected from the server.
1 parent 51935ed commit 56cd9c6

File tree

5 files changed

+162
-29
lines changed

5 files changed

+162
-29
lines changed

src/FreeDSx/Ldap/Protocol/ServerProtocolHandler/ServerPagingHandler.php

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,35 @@ public function handleRequest(
8181
);
8282
$pagingRequest = $this->findOrMakePagingRequest($message);
8383

84-
$response = $this->handlePaging(
85-
$context,
86-
$pagingRequest,
87-
$message
88-
);
84+
$response = null;
85+
$controls = [];
86+
try {
87+
$response = $this->handlePaging(
88+
$context,
89+
$pagingRequest,
90+
$message
91+
);
92+
$searchResult = ServerSearchResult::makeSuccessResult($response->getEntries());
93+
$controls[] = new PagingControl(
94+
$response->getRemaining(),
95+
$response->isComplete()
96+
? ''
97+
: $pagingRequest->getNextCookie()
98+
);
99+
} catch (OperationException $e) {
100+
$searchResult = ServerSearchResult::makeErrorResult(
101+
$e->getCode(),
102+
$e->getMessage()
103+
);
104+
$controls[] = new PagingControl(
105+
0,
106+
$pagingRequest->getCookie()
107+
);
108+
}
89109

90110
$pagingRequest->markProcessed();
91111

92-
if ($response->isComplete()) {
112+
if ($response === null || $response->isComplete()) {
93113
$this->requestHistory->pagingRequest()
94114
->remove($pagingRequest);
95115
$this->pagingHandler->remove(
@@ -99,13 +119,10 @@ public function handleRequest(
99119
}
100120

101121
$this->sendEntriesToClient(
102-
$response->getEntries(),
122+
$searchResult,
103123
$message,
104124
$queue,
105-
new PagingControl(
106-
$response->getRemaining(),
107-
$response->isComplete() ? '' : $pagingRequest->getNextCookie()
108-
)
125+
...$controls
109126
);
110127
}
111128

src/FreeDSx/Ldap/Protocol/ServerProtocolHandler/ServerPagingUnsupportedHandler.php

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,20 @@ public function handleRequest(
6060
);
6161
}
6262

63-
$entries = $dispatcher->search(
64-
$context,
65-
$request
66-
);
63+
try {
64+
$searchResult = ServerSearchResult::makeSuccessResult($dispatcher->search(
65+
$context,
66+
$request
67+
));
68+
} catch (OperationException $e) {
69+
$searchResult = ServerSearchResult::makeErrorResult(
70+
$e->getCode(),
71+
$e->getMessage()
72+
);
73+
}
6774

6875
$this->sendEntriesToClient(
69-
$entries,
76+
$searchResult,
7077
$message,
7178
$queue
7279
);

src/FreeDSx/Ldap/Protocol/ServerProtocolHandler/ServerSearchHandler.php

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

1212
namespace FreeDSx\Ldap\Protocol\ServerProtocolHandler;
1313

14+
use FreeDSx\Ldap\Exception\OperationException;
1415
use FreeDSx\Ldap\Protocol\LdapMessageRequest;
1516
use FreeDSx\Ldap\Protocol\Queue\ServerQueue;
1617
use FreeDSx\Ldap\Server\RequestContext;
@@ -42,13 +43,20 @@ public function handleRequest(
4243
);
4344
$request = $this->getSearchRequestFromMessage($message);
4445

45-
$entries = $dispatcher->search(
46-
$context,
47-
$request
48-
);
46+
try {
47+
$searchResult = ServerSearchResult::makeSuccessResult($dispatcher->search(
48+
$context,
49+
$request
50+
));
51+
} catch (OperationException $e) {
52+
$searchResult = ServerSearchResult::makeErrorResult(
53+
$e->getCode(),
54+
$e->getMessage()
55+
);
56+
}
4957

5058
$this->sendEntriesToClient(
51-
$entries,
59+
$searchResult,
5260
$message,
5361
$queue
5462
);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of the FreeDSx LDAP package.
7+
*
8+
* (c) Chad Sikorra <Chad.Sikorra@gmail.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace FreeDSx\Ldap\Protocol\ServerProtocolHandler;
15+
16+
use FreeDSx\Ldap\Entry\Entries;
17+
use FreeDSx\Ldap\Exception\InvalidArgumentException;
18+
use FreeDSx\Ldap\Operation\ResultCode;
19+
20+
final class ServerSearchResult
21+
{
22+
/**
23+
* @var Entries|null
24+
*/
25+
private $entries;
26+
27+
/**
28+
* @var int
29+
*/
30+
private $resultCode;
31+
32+
/**
33+
* @var string
34+
*/
35+
private $diagnosticMessage;
36+
37+
private function __construct(
38+
?Entries $entries,
39+
int $resultCode = ResultCode::SUCCESS,
40+
string $diagnosticMessage = ''
41+
) {
42+
$this->entries = $entries;
43+
$this->resultCode = $resultCode;
44+
$this->diagnosticMessage = $diagnosticMessage;
45+
}
46+
47+
/**
48+
* Make a successful server search result representation.
49+
*/
50+
public static function makeSuccessResult(
51+
Entries $entries,
52+
string $diagnosticMessage = ''
53+
): self {
54+
return new self(
55+
$entries,
56+
ResultCode::SUCCESS,
57+
$diagnosticMessage
58+
);
59+
}
60+
61+
/**
62+
* Make an error result for server search result representation. This could occur for any reason, such as a base DN
63+
* not existing. This result MUST not return a success result code.
64+
*/
65+
public static function makeErrorResult(
66+
int $resultCode,
67+
string $diagnosticMessage = '',
68+
?Entries $entries = null
69+
): self {
70+
if ($resultCode === ResultCode::SUCCESS) {
71+
throw new InvalidArgumentException('You must not return a success result code on a search error.');
72+
}
73+
74+
return new self(
75+
$entries,
76+
ResultCode::SUCCESS,
77+
$diagnosticMessage
78+
);
79+
}
80+
81+
public function getEntries(): ?Entries
82+
{
83+
return $this->entries;
84+
}
85+
86+
public function getResultCode(): int
87+
{
88+
return $this->resultCode;
89+
}
90+
91+
public function getDiagnosticMessage(): string
92+
{
93+
return $this->diagnosticMessage;
94+
}
95+
}

src/FreeDSx/Ldap/Protocol/ServerProtocolHandler/ServerSearchTrait.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,35 @@
2727
trait ServerSearchTrait
2828
{
2929
/**
30-
* @param Entries $entries
30+
* @param ServerSearchResult $searchResult
3131
* @param LdapMessageRequest $message
3232
* @param ServerQueue $queue
3333
* @return void
3434
*/
3535
private function sendEntriesToClient(
36-
Entries $entries,
36+
ServerSearchResult $searchResult,
3737
LdapMessageRequest $message,
3838
ServerQueue $queue,
3939
Control ...$controls
4040
): void {
4141
$messages = [];
42+
$entries = $searchResult->getEntries();
4243

43-
foreach ($entries->toArray() as $entry) {
44-
$messages[] = new LdapMessageResponse(
45-
$message->getMessageId(),
46-
new SearchResultEntry($entry)
47-
);
44+
if ($entries !== null) {
45+
foreach ($entries->toArray() as $entry) {
46+
$messages[] = new LdapMessageResponse(
47+
$message->getMessageId(),
48+
new SearchResultEntry($entry)
49+
);
50+
}
4851
}
4952

5053
$messages[] = new LdapMessageResponse(
5154
$message->getMessageId(),
52-
new SearchResultDone(ResultCode::SUCCESS),
55+
new SearchResultDone(
56+
$searchResult->getResultCode(),
57+
$searchResult->getDiagnosticMessage()
58+
),
5359
...$controls
5460
);
5561

0 commit comments

Comments
 (0)