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