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\Operation\Response; 13 14use FreeDSx\Asn1\Asn1; 15use FreeDSx\Asn1\Exception\EncoderException; 16use FreeDSx\Asn1\Exception\PartialPduException; 17use FreeDSx\Asn1\Type\AbstractType; 18use FreeDSx\Asn1\Type\SequenceType; 19use FreeDSx\Ldap\Exception\ProtocolException; 20use FreeDSx\Ldap\Operation\LdapResult; 21use FreeDSx\Ldap\Protocol\LdapEncoder; 22use FreeDSx\Ldap\Protocol\ProtocolElementInterface; 23 24/** 25 * RFC 4511, 4.12 26 * 27 * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { 28 * COMPONENTS OF LDAPResult, 29 * responseName [10] LDAPOID OPTIONAL, 30 * responseValue [11] OCTET STRING OPTIONAL } 31 * 32 * @author Chad Sikorra <Chad.Sikorra@gmail.com> 33 */ 34class ExtendedResponse extends LdapResult 35{ 36 /** 37 * @var int 38 */ 39 protected $tagNumber = 24; 40 41 /** 42 * RFC 4511, 4.4.1. Used by the server to notify the client it is terminating the LDAP session. 43 */ 44 public const OID_NOTICE_OF_DISCONNECTION = '1.3.6.1.4.1.1466.20036'; 45 46 /** 47 * @var null|string 48 */ 49 protected $responseName; 50 51 /** 52 * @var null|string|AbstractType|ProtocolElementInterface 53 */ 54 protected $responseValue; 55 56 /** 57 * @param LdapResult $result 58 * @param null|string $responseName 59 * @param null|string $responseValue 60 */ 61 public function __construct(LdapResult $result, ?string $responseName = null, $responseValue = null) 62 { 63 $this->responseValue = $responseValue; 64 $this->responseName = $responseName; 65 parent::__construct($result->getResultCode(), $result->getDn(), $result->getDiagnosticMessage(), ...$result->getReferrals()); 66 } 67 68 /** 69 * Get the OID name of the extended response. 70 * 71 * @return null|string 72 */ 73 public function getName(): ?string 74 { 75 return $this->responseName; 76 } 77 78 /** 79 * Get the value of the extended response. 80 * 81 * @return null|string 82 */ 83 public function getValue(): ?string 84 { 85 return is_string($this->responseValue) ? $this->responseValue : null; 86 } 87 88 /** 89 * {@inheritDoc} 90 * @return self 91 * @throws EncoderException 92 */ 93 public static function fromAsn1(AbstractType $type) 94 { 95 return new self( 96 self::createLdapResult($type), 97 ...self::parseExtendedResponse($type) 98 ); 99 } 100 101 /** 102 * @return AbstractType 103 * @throws ProtocolException 104 * @throws EncoderException 105 */ 106 public function toAsn1(): AbstractType 107 { 108 /** @var SequenceType $asn1 */ 109 $asn1 = parent::toAsn1(); 110 111 if ($this->responseName !== null) { 112 $asn1->addChild(Asn1::context(10, Asn1::octetString($this->responseName))); 113 } 114 if ($this->responseValue !== null) { 115 $encoder = new LdapEncoder(); 116 $value = $this->responseValue; 117 if ($value instanceof AbstractType) { 118 $value = $encoder->encode($value); 119 } elseif ($value instanceof ProtocolElementInterface) { 120 $value = $encoder->encode($value->toAsn1()); 121 } 122 $asn1->addChild(Asn1::context(11, Asn1::octetString($value))); 123 } 124 125 return $asn1; 126 } 127 128 /** 129 * @param AbstractType $type 130 * @return array 131 */ 132 protected static function parseExtendedResponse(AbstractType $type) 133 { 134 $info = [0 => null, 1 => null]; 135 136 foreach ($type->getChildren() as $child) { 137 if ($child->getTagNumber() === 10) { 138 $info[0] = $child->getValue(); 139 } elseif ($child->getTagNumber() === 11) { 140 $info[1] = $child->getValue(); 141 } 142 } 143 144 return $info; 145 } 146 147 /** 148 * @param AbstractType $type 149 * @return LdapResult 150 * @throws ProtocolException 151 * @throws EncoderException 152 */ 153 protected static function createLdapResult(AbstractType $type) 154 { 155 [$resultCode, $dn, $diagnosticMessage, $referrals] = self::parseResultData($type); 156 157 return new LdapResult($resultCode, $dn, $diagnosticMessage, ...$referrals); 158 } 159 160 /** 161 * @param AbstractType $type 162 * @return AbstractType|null 163 * @throws ProtocolException 164 * @throws EncoderException 165 * @throws PartialPduException 166 */ 167 protected static function decodeEncodedValue(AbstractType $type) 168 { 169 if (!$type instanceof SequenceType) { 170 throw new ProtocolException('The received control is malformed. Unable to get the encoded value.'); 171 } 172 [1 => $value] = self::parseExtendedResponse($type); 173 174 return $value === null ? null : (new LdapEncoder())->decode($value); 175 } 176} 177