xref: /plugin/pureldap/vendor/freedsx/ldap/src/FreeDSx/Ldap/Control/PwdPolicyResponseControl.php (revision dad993c57a70866aa1db59c43f043769c2eb7ed0)
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