1<?php
2
3/**
4 * This file is part of the FreeDSx LDAP package.
5 *
6 * (c) Chad Sikorra <Chad.Sikorra@gmail.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
12namespace FreeDSx\Ldap\Protocol\Factory;
13
14use FreeDSx\Ldap\Control\Control;
15use FreeDSx\Ldap\Control\ControlBag;
16use FreeDSx\Ldap\Operation\Request\ExtendedRequest;
17use FreeDSx\Ldap\Operation\Request\RequestInterface;
18use FreeDSx\Ldap\Operation\Request\SearchRequest;
19use FreeDSx\Ldap\Operation\Request\UnbindRequest;
20use FreeDSx\Ldap\Protocol\ServerProtocolHandler;
21use FreeDSx\Ldap\Protocol\ServerProtocolHandler\ServerProtocolHandlerInterface;
22use FreeDSx\Ldap\Server\HandlerFactoryInterface;
23use FreeDSx\Ldap\Server\RequestHistory;
24
25/**
26 * Determines the correct handler for the request.
27 *
28 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
29 */
30class ServerProtocolHandlerFactory
31{
32    /**
33     * @var HandlerFactoryInterface
34     */
35    private $handlerFactory;
36
37    /**
38     * @var RequestHistory
39     */
40    private $requestHistory;
41
42    public function __construct(
43        HandlerFactoryInterface $handlerFactory,
44        RequestHistory $requestHistory
45    ) {
46        $this->handlerFactory = $handlerFactory;
47        $this->requestHistory = $requestHistory;
48    }
49
50    public function get(
51        RequestInterface $request,
52        ControlBag $controls
53    ): ServerProtocolHandlerInterface {
54        if ($request instanceof ExtendedRequest && $request->getName() === ExtendedRequest::OID_WHOAMI) {
55            return new ServerProtocolHandler\ServerWhoAmIHandler();
56        } elseif ($request instanceof ExtendedRequest && $request->getName() === ExtendedRequest::OID_START_TLS) {
57            return new ServerProtocolHandler\ServerStartTlsHandler();
58        } elseif ($this->isRootDseSearch($request)) {
59            return $this->getRootDseHandler();
60        } elseif ($this->isPagingSearch($request, $controls)) {
61            return $this->getPagingHandler();
62        } elseif ($request instanceof SearchRequest) {
63            return new ServerProtocolHandler\ServerSearchHandler();
64        } elseif ($request instanceof UnbindRequest) {
65            return new ServerProtocolHandler\ServerUnbindHandler();
66        } else {
67            return new ServerProtocolHandler\ServerDispatchHandler();
68        }
69    }
70
71    private function isRootDseSearch(RequestInterface $request): bool
72    {
73        if (!$request instanceof SearchRequest) {
74            return false;
75        }
76
77        return $request->getScope() === SearchRequest::SCOPE_BASE_OBJECT
78                && ((string)$request->getBaseDn() === '');
79    }
80
81    private function isPagingSearch(
82        RequestInterface $request,
83        ControlBag $controls
84    ): bool {
85        return $request instanceof SearchRequest
86            && $controls->has(Control::OID_PAGING);
87    }
88
89    private function getRootDseHandler(): ServerProtocolHandler\ServerRootDseHandler
90    {
91        $rootDseHandler = $this->handlerFactory->makeRootDseHandler();
92
93        return new ServerProtocolHandler\ServerRootDseHandler($rootDseHandler);
94    }
95
96    private function getPagingHandler(): ServerProtocolHandlerInterface
97    {
98        $pagingHandler = $this->handlerFactory->makePagingHandler();
99
100        if (!$pagingHandler) {
101            return new ServerProtocolHandler\ServerPagingUnsupportedHandler();
102        }
103
104        return new ServerProtocolHandler\ServerPagingHandler(
105            $pagingHandler,
106            $this->requestHistory
107        );
108    }
109}
110