1<?php
2/**
3 * This file is part of the FreeDSx LDAP package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.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
11namespace FreeDSx\Ldap\Protocol\ClientProtocolHandler;
12
13use FreeDSx\Ldap\Exception\BindException;
14use FreeDSx\Ldap\Exception\OperationException;
15use FreeDSx\Ldap\Operation\LdapResult;
16use FreeDSx\Ldap\Operation\Request\BindRequest;
17use FreeDSx\Ldap\Operation\ResultCode;
18use FreeDSx\Ldap\Protocol\LdapMessageRequest;
19use FreeDSx\Ldap\Protocol\LdapMessageResponse;
20use FreeDSx\Ldap\Protocol\Queue\ClientQueue;
21
22/**
23 * Logic for handling basic operations.
24 *
25 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
26 */
27class ClientBasicHandler implements RequestHandlerInterface, ResponseHandlerInterface
28{
29    /**
30     * RFC 4511, A.1. These are considered result codes that do not indicate an error condition.
31     */
32    protected const NON_ERROR_CODES = [
33        ResultCode::SUCCESS,
34        ResultCode::COMPARE_FALSE,
35        ResultCode::COMPARE_TRUE,
36        ResultCode::REFERRAL,
37        ResultCode::SASL_BIND_IN_PROGRESS,
38    ];
39
40    /**
41     * {@inheritDoc}
42     */
43    public function handleRequest(ClientProtocolContext $context): ?LdapMessageResponse
44    {
45        $queue = $context->getQueue();
46        $message = $context->messageToSend();
47        $queue->sendMessage($message);
48
49        return $queue->getMessage($message->getMessageId());
50    }
51
52    /**
53     * {@inheritDoc}
54     */
55    public function handleResponse(LdapMessageRequest $messageTo, LdapMessageResponse $messageFrom, ClientQueue $queue, array $options): ?LdapMessageResponse
56    {
57        $result = $messageFrom->getResponse();
58
59        # No action to take if we received something that isn't an LDAP Result, or on success.
60        if (!$result instanceof LdapResult || $result->getResultCode() === ResultCode::SUCCESS) {
61            return $messageFrom;
62        }
63
64        # The success code above should satisfy the majority of cases. This checks if the result code is really a non
65        # error condition defined in RFC 4511, A.1
66        if (\in_array($result->getResultCode(), self::NON_ERROR_CODES, true)) {
67            return $messageFrom;
68        }
69
70        if ($messageTo->getRequest() instanceof BindRequest) {
71            throw new BindException(
72                sprintf('Unable to bind to LDAP. %s', $result->getDiagnosticMessage()),
73                $result->getResultCode()
74            );
75        }
76
77        throw new OperationException($result->getDiagnosticMessage(), $result->getResultCode());
78    }
79}
80