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\ServerProtocolHandler;
12
13use FreeDSx\Ldap\Entry\Entry;
14use FreeDSx\Ldap\Operation\Request\ExtendedRequest;
15use FreeDSx\Ldap\Operation\Request\SearchRequest;
16use FreeDSx\Ldap\Operation\Response\SearchResultDone;
17use FreeDSx\Ldap\Operation\Response\SearchResultEntry;
18use FreeDSx\Ldap\Operation\ResultCode;
19use FreeDSx\Ldap\Protocol\LdapMessageRequest;
20use FreeDSx\Ldap\Protocol\LdapMessageResponse;
21use FreeDSx\Ldap\Protocol\Queue\ServerQueue;
22use FreeDSx\Ldap\Server\RequestContext;
23use FreeDSx\Ldap\Server\RequestHandler\RequestHandlerInterface;
24use FreeDSx\Ldap\Server\RequestHandler\RootDseHandlerInterface;
25use FreeDSx\Ldap\Server\Token\TokenInterface;
26
27/**
28 * Handles RootDSE based search requests.
29 *
30 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
31 */
32class ServerRootDseHandler implements ServerProtocolHandlerInterface
33{
34    /**
35     * {@inheritDoc}
36     */
37    public function handleRequest(LdapMessageRequest $message, TokenInterface $token, RequestHandlerInterface $dispatcher, ServerQueue $queue, array $options): void
38    {
39        $entry = Entry::fromArray('', [
40            'namingContexts' => $options['dse_naming_contexts'] ?? '',
41            'supportedExtension' => [
42                ExtendedRequest::OID_WHOAMI,
43            ],
44            'supportedLDAPVersion' => ['3'],
45            'vendorName' => $options['dse_vendor_name'] ?? '',
46        ]);
47        if (isset($options['ssl_cert'])) {
48            $entry->set('supportedExtension', ExtendedRequest::OID_START_TLS);
49        }
50        if (isset($options['vendor_version'])) {
51            $entry->set('vendorVersion', $options['vendor_version']);
52        }
53        if (isset($options['alt_server'])) {
54            $entry->set('altServer', $options['alt_server']);
55        }
56
57        /** @var SearchRequest $request */
58        $request = $message->getRequest();
59        $this->filterEntryAttributes($request, $entry);
60
61        if ($dispatcher instanceof RootDseHandlerInterface) {
62            $entry = $dispatcher->rootDse(
63                new RequestContext($message->controls(), $token),
64                $request,
65                $entry
66            );
67        }
68
69        $queue->sendMessage(
70            new LdapMessageResponse(
71                $message->getMessageId(),
72                new SearchResultEntry($entry)
73            ),
74            new LdapMessageResponse(
75                $message->getMessageId(),
76                new SearchResultDone(ResultCode::SUCCESS)
77            )
78        );
79    }
80
81    /**
82     * Filters attributes from an entry to return only what was requested.
83     */
84    protected function filterEntryAttributes(SearchRequest $request, Entry $entry): void
85    {
86        if (\count($request->getAttributes()) !== 0) {
87            foreach ($entry->getAttributes() as $dseAttr) {
88                $found = false;
89                foreach ($request->getAttributes() as $attribute) {
90                    if ($attribute->equals($dseAttr)) {
91                        $found = true;
92                        break;
93                    }
94                }
95                if ($found === true && $request->getAttributesOnly()) {
96                    $dseAttr->reset();
97                }
98                if ($found === false) {
99                    $entry->reset($dseAttr);
100                    $entry->changes()->reset();
101                }
102            }
103        }
104        if ($request->getAttributesOnly()) {
105            foreach ($entry->getAttributes() as $attribute) {
106                $attribute->reset();
107            }
108        }
109    }
110}
111