10b3fd2d3SAndreas Gohr<?php 2*dad993c5SAndreas Gohr 30b3fd2d3SAndreas Gohr/** 40b3fd2d3SAndreas Gohr * This file is part of the FreeDSx LDAP package. 50b3fd2d3SAndreas Gohr * 60b3fd2d3SAndreas Gohr * (c) Chad Sikorra <Chad.Sikorra@gmail.com> 70b3fd2d3SAndreas Gohr * 80b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE 90b3fd2d3SAndreas Gohr * file that was distributed with this source code. 100b3fd2d3SAndreas Gohr */ 110b3fd2d3SAndreas Gohr 120b3fd2d3SAndreas Gohrnamespace FreeDSx\Ldap\Control; 130b3fd2d3SAndreas Gohr 140b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Asn1; 15*dad993c5SAndreas Gohruse FreeDSx\Asn1\Exception\EncoderException; 16*dad993c5SAndreas Gohruse FreeDSx\Asn1\Exception\PartialPduException; 170b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\AbstractType; 180b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\IncompleteType; 190b3fd2d3SAndreas Gohruse FreeDSx\Asn1\Type\SequenceType; 200b3fd2d3SAndreas Gohruse FreeDSx\Ldap\Exception\ProtocolException; 210b3fd2d3SAndreas Gohruse FreeDSx\Ldap\Protocol\LdapEncoder; 220b3fd2d3SAndreas Gohr 230b3fd2d3SAndreas Gohr/** 240b3fd2d3SAndreas Gohr * Represents a password policy response. draft-behera-ldap-password-policy-09 250b3fd2d3SAndreas Gohr * 260b3fd2d3SAndreas Gohr * PasswordPolicyResponseValue ::= SEQUENCE { 270b3fd2d3SAndreas Gohr * warning [0] CHOICE { 280b3fd2d3SAndreas Gohr * timeBeforeExpiration [0] INTEGER (0 .. maxInt), 290b3fd2d3SAndreas Gohr * graceAuthNsRemaining [1] INTEGER (0 .. maxInt) } OPTIONAL, 300b3fd2d3SAndreas Gohr * error [1] ENUMERATED { 310b3fd2d3SAndreas Gohr * passwordExpired (0), 320b3fd2d3SAndreas Gohr * accountLocked (1), 330b3fd2d3SAndreas Gohr * changeAfterReset (2), 340b3fd2d3SAndreas Gohr * passwordModNotAllowed (3), 350b3fd2d3SAndreas Gohr * mustSupplyOldPassword (4), 360b3fd2d3SAndreas Gohr * insufficientPasswordQuality (5), 370b3fd2d3SAndreas Gohr * passwordTooShort (6), 380b3fd2d3SAndreas Gohr * passwordTooYoung (7), 390b3fd2d3SAndreas Gohr * passwordInHistory (8) } OPTIONAL } 400b3fd2d3SAndreas Gohr * 410b3fd2d3SAndreas Gohr * @author Chad Sikorra <Chad.Sikorra@gmail.com> 420b3fd2d3SAndreas Gohr */ 430b3fd2d3SAndreas Gohrclass PwdPolicyResponseControl extends Control 440b3fd2d3SAndreas Gohr{ 450b3fd2d3SAndreas Gohr /** 460b3fd2d3SAndreas Gohr * @var int|null 470b3fd2d3SAndreas Gohr */ 480b3fd2d3SAndreas Gohr protected $timeBeforeExpiration; 490b3fd2d3SAndreas Gohr 500b3fd2d3SAndreas Gohr /** 510b3fd2d3SAndreas Gohr * @var int|null 520b3fd2d3SAndreas Gohr */ 530b3fd2d3SAndreas Gohr protected $graceAuthRemaining; 540b3fd2d3SAndreas Gohr 550b3fd2d3SAndreas Gohr /** 560b3fd2d3SAndreas Gohr * @var int|null 570b3fd2d3SAndreas Gohr */ 580b3fd2d3SAndreas Gohr protected $error; 590b3fd2d3SAndreas Gohr 600b3fd2d3SAndreas Gohr /** 610b3fd2d3SAndreas Gohr * @param int|null $timeBeforeExpiration 620b3fd2d3SAndreas Gohr * @param int|null $graceAuthRemaining 630b3fd2d3SAndreas Gohr * @param int|null $error 640b3fd2d3SAndreas Gohr */ 650b3fd2d3SAndreas Gohr public function __construct(?int $timeBeforeExpiration = null, ?int $graceAuthRemaining = null, ?int $error = null) 660b3fd2d3SAndreas Gohr { 670b3fd2d3SAndreas Gohr $this->timeBeforeExpiration = $timeBeforeExpiration; 680b3fd2d3SAndreas Gohr $this->graceAuthRemaining = $graceAuthRemaining; 690b3fd2d3SAndreas Gohr $this->error = $error; 700b3fd2d3SAndreas Gohr parent::__construct(self::OID_PWD_POLICY); 710b3fd2d3SAndreas Gohr } 720b3fd2d3SAndreas Gohr 730b3fd2d3SAndreas Gohr /** 740b3fd2d3SAndreas Gohr * @return int|null 750b3fd2d3SAndreas Gohr */ 760b3fd2d3SAndreas Gohr public function getTimeBeforeExpiration(): ?int 770b3fd2d3SAndreas Gohr { 780b3fd2d3SAndreas Gohr return $this->timeBeforeExpiration; 790b3fd2d3SAndreas Gohr } 800b3fd2d3SAndreas Gohr 810b3fd2d3SAndreas Gohr /** 820b3fd2d3SAndreas Gohr * @return int|null 830b3fd2d3SAndreas Gohr */ 840b3fd2d3SAndreas Gohr public function getGraceAttemptsRemaining(): ?int 850b3fd2d3SAndreas Gohr { 860b3fd2d3SAndreas Gohr return $this->graceAuthRemaining; 870b3fd2d3SAndreas Gohr } 880b3fd2d3SAndreas Gohr 890b3fd2d3SAndreas Gohr /** 900b3fd2d3SAndreas Gohr * @return int|null 910b3fd2d3SAndreas Gohr */ 920b3fd2d3SAndreas Gohr public function getError(): ?int 930b3fd2d3SAndreas Gohr { 940b3fd2d3SAndreas Gohr return $this->error; 950b3fd2d3SAndreas Gohr } 960b3fd2d3SAndreas Gohr 970b3fd2d3SAndreas Gohr /** 98*dad993c5SAndreas Gohr * @return AbstractType 99*dad993c5SAndreas Gohr * @throws ProtocolException 100*dad993c5SAndreas Gohr * @throws EncoderException 1010b3fd2d3SAndreas Gohr */ 1020b3fd2d3SAndreas Gohr public function toAsn1(): AbstractType 1030b3fd2d3SAndreas Gohr { 1040b3fd2d3SAndreas Gohr $response = Asn1::sequence(); 1050b3fd2d3SAndreas Gohr $warning = null; 1060b3fd2d3SAndreas Gohr 1070b3fd2d3SAndreas Gohr if ($this->graceAuthRemaining !== null && $this->timeBeforeExpiration !== null) { 1080b3fd2d3SAndreas Gohr throw new ProtocolException('The password policy response cannot have both a time expiration and a grace auth value.'); 1090b3fd2d3SAndreas Gohr } 1100b3fd2d3SAndreas Gohr if ($this->timeBeforeExpiration !== null) { 1110b3fd2d3SAndreas Gohr $warning = Asn1::context(0, Asn1::sequence( 1120b3fd2d3SAndreas Gohr Asn1::context(0, Asn1::integer($this->timeBeforeExpiration)) 1130b3fd2d3SAndreas Gohr )); 1140b3fd2d3SAndreas Gohr } 1150b3fd2d3SAndreas Gohr if ($this->graceAuthRemaining !== null) { 1160b3fd2d3SAndreas Gohr $warning = Asn1::context(0, Asn1::sequence( 1170b3fd2d3SAndreas Gohr Asn1::context(1, Asn1::integer($this->graceAuthRemaining)) 1180b3fd2d3SAndreas Gohr )); 1190b3fd2d3SAndreas Gohr } 1200b3fd2d3SAndreas Gohr 1210b3fd2d3SAndreas Gohr if ($warning !== null) { 1220b3fd2d3SAndreas Gohr $response->addChild($warning); 1230b3fd2d3SAndreas Gohr } 1240b3fd2d3SAndreas Gohr if ($this->error !== null) { 1250b3fd2d3SAndreas Gohr $response->addChild(Asn1::context(1, Asn1::enumerated($this->error))); 1260b3fd2d3SAndreas Gohr } 1270b3fd2d3SAndreas Gohr $this->controlValue = $response; 1280b3fd2d3SAndreas Gohr 1290b3fd2d3SAndreas Gohr return parent::toAsn1(); 1300b3fd2d3SAndreas Gohr } 1310b3fd2d3SAndreas Gohr 1320b3fd2d3SAndreas Gohr /** 133*dad993c5SAndreas Gohr * {@inheritDoc} 134*dad993c5SAndreas Gohr * @return Control 135*dad993c5SAndreas Gohr * @throws EncoderException 136*dad993c5SAndreas Gohr * @throws PartialPduException 1370b3fd2d3SAndreas Gohr */ 1380b3fd2d3SAndreas Gohr public static function fromAsn1(AbstractType $type) 1390b3fd2d3SAndreas Gohr { 1400b3fd2d3SAndreas Gohr /** @var SequenceType $response */ 1410b3fd2d3SAndreas Gohr $response = self::decodeEncodedValue($type); 1420b3fd2d3SAndreas Gohr 1430b3fd2d3SAndreas Gohr $error = null; 1440b3fd2d3SAndreas Gohr $timeBeforeExpiration = null; 1450b3fd2d3SAndreas Gohr $graceAttemptsRemaining = null; 1460b3fd2d3SAndreas Gohr 1470b3fd2d3SAndreas Gohr $encoder = new LdapEncoder(); 1480b3fd2d3SAndreas Gohr foreach ($response->getChildren() as $child) { 1490b3fd2d3SAndreas Gohr if (!$child instanceof IncompleteType) { 1500b3fd2d3SAndreas Gohr throw new ProtocolException('The ASN1 structure for the pwdPolicy control is malformed.'); 1510b3fd2d3SAndreas Gohr } 1520b3fd2d3SAndreas Gohr if ($child->getTagNumber() === 0) { 1530b3fd2d3SAndreas Gohr $warnings = $encoder->complete($child, AbstractType::TAG_TYPE_SEQUENCE, [ 1540b3fd2d3SAndreas Gohr AbstractType::TAG_CLASS_CONTEXT_SPECIFIC => [ 1550b3fd2d3SAndreas Gohr 0 => AbstractType::TAG_TYPE_INTEGER, 1560b3fd2d3SAndreas Gohr 1 => AbstractType::TAG_TYPE_INTEGER, 1570b3fd2d3SAndreas Gohr ], 1580b3fd2d3SAndreas Gohr ]); 1590b3fd2d3SAndreas Gohr /** @var AbstractType $warning */ 1600b3fd2d3SAndreas Gohr foreach ($warnings->getChildren() as $warning) { 1610b3fd2d3SAndreas Gohr if ($warning->getTagNumber() === 0) { 1620b3fd2d3SAndreas Gohr $timeBeforeExpiration = $warning->getValue(); 1630b3fd2d3SAndreas Gohr break; 1640b3fd2d3SAndreas Gohr } elseif ($warning->getTagNumber() === 1) { 1650b3fd2d3SAndreas Gohr $graceAttemptsRemaining = $warning->getValue(); 1660b3fd2d3SAndreas Gohr break; 1670b3fd2d3SAndreas Gohr } 1680b3fd2d3SAndreas Gohr } 1690b3fd2d3SAndreas Gohr } elseif ($child->getTagNumber() === 1) { 1700b3fd2d3SAndreas Gohr $error = $encoder->complete($child, AbstractType::TAG_TYPE_ENUMERATED)->getValue(); 1710b3fd2d3SAndreas Gohr } 1720b3fd2d3SAndreas Gohr } 1730b3fd2d3SAndreas Gohr $control = new self($timeBeforeExpiration, $graceAttemptsRemaining, $error); 1740b3fd2d3SAndreas Gohr 1750b3fd2d3SAndreas Gohr return self::mergeControlData($control, $type); 1760b3fd2d3SAndreas Gohr } 1770b3fd2d3SAndreas Gohr} 178