xref: /plugin/pureldap/vendor/freedsx/sasl/src/FreeDSx/Sasl/Challenge/PlainChallenge.php (revision 0b3fd2d31e4d1997548a8fbc53fa771027c4a47f)
1*0b3fd2d3SAndreas Gohr<?php
2*0b3fd2d3SAndreas Gohr
3*0b3fd2d3SAndreas Gohr/**
4*0b3fd2d3SAndreas Gohr * This file is part of the FreeDSx SASL package.
5*0b3fd2d3SAndreas Gohr *
6*0b3fd2d3SAndreas Gohr * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
7*0b3fd2d3SAndreas Gohr *
8*0b3fd2d3SAndreas Gohr * For the full copyright and license information, please view the LICENSE
9*0b3fd2d3SAndreas Gohr * file that was distributed with this source code.
10*0b3fd2d3SAndreas Gohr */
11*0b3fd2d3SAndreas Gohr
12*0b3fd2d3SAndreas Gohrnamespace FreeDSx\Sasl\Challenge;
13*0b3fd2d3SAndreas Gohr
14*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Encoder\PlainEncoder;
15*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Exception\SaslException;
16*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Message;
17*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\SaslContext;
18*0b3fd2d3SAndreas Gohr
19*0b3fd2d3SAndreas Gohr/**
20*0b3fd2d3SAndreas Gohr * The PLAIN challenge / response class.
21*0b3fd2d3SAndreas Gohr *
22*0b3fd2d3SAndreas Gohr * @author Chad Sikorra <Chad.Sikorra@gmail.com>
23*0b3fd2d3SAndreas Gohr */
24*0b3fd2d3SAndreas Gohrclass PlainChallenge implements ChallengeInterface
25*0b3fd2d3SAndreas Gohr{
26*0b3fd2d3SAndreas Gohr    /**
27*0b3fd2d3SAndreas Gohr     * @var PlainEncoder
28*0b3fd2d3SAndreas Gohr     */
29*0b3fd2d3SAndreas Gohr    protected $encoder;
30*0b3fd2d3SAndreas Gohr
31*0b3fd2d3SAndreas Gohr    /**
32*0b3fd2d3SAndreas Gohr     * @var SaslContext
33*0b3fd2d3SAndreas Gohr     */
34*0b3fd2d3SAndreas Gohr    protected $context;
35*0b3fd2d3SAndreas Gohr
36*0b3fd2d3SAndreas Gohr    public function __construct(bool $isServerMode = false)
37*0b3fd2d3SAndreas Gohr    {
38*0b3fd2d3SAndreas Gohr        $this->encoder = new PlainEncoder();
39*0b3fd2d3SAndreas Gohr        $this->context = new SaslContext();
40*0b3fd2d3SAndreas Gohr        $this->context->setIsServerMode($isServerMode);
41*0b3fd2d3SAndreas Gohr    }
42*0b3fd2d3SAndreas Gohr
43*0b3fd2d3SAndreas Gohr    /**
44*0b3fd2d3SAndreas Gohr     * {@inheritDoc}
45*0b3fd2d3SAndreas Gohr     */
46*0b3fd2d3SAndreas Gohr    public function challenge(?string $received = null, array $options = []): SaslContext
47*0b3fd2d3SAndreas Gohr    {
48*0b3fd2d3SAndreas Gohr        $received = $received === null ? null : $this->encoder->decode($received, $this->context);
49*0b3fd2d3SAndreas Gohr
50*0b3fd2d3SAndreas Gohr        if ($this->context->isServerMode()) {
51*0b3fd2d3SAndreas Gohr            return $this->serverProcess($received, $options);
52*0b3fd2d3SAndreas Gohr        } else {
53*0b3fd2d3SAndreas Gohr            return $this->clientProcess($options);
54*0b3fd2d3SAndreas Gohr        }
55*0b3fd2d3SAndreas Gohr    }
56*0b3fd2d3SAndreas Gohr
57*0b3fd2d3SAndreas Gohr    protected function serverProcess(?Message $message, array $options): SaslContext
58*0b3fd2d3SAndreas Gohr    {
59*0b3fd2d3SAndreas Gohr        if ($message === null) {
60*0b3fd2d3SAndreas Gohr            return $this->context;
61*0b3fd2d3SAndreas Gohr        }
62*0b3fd2d3SAndreas Gohr        if (!(isset($options['validate']) && is_callable($options['validate']))) {
63*0b3fd2d3SAndreas Gohr            throw new SaslException('You must pass a callable validate option to the plain mechanism in server mode.');
64*0b3fd2d3SAndreas Gohr        }
65*0b3fd2d3SAndreas Gohr        $authzId = $message->get('authzid');
66*0b3fd2d3SAndreas Gohr        $authcId = $message->get('authcid');
67*0b3fd2d3SAndreas Gohr        $password = $message->get('password');
68*0b3fd2d3SAndreas Gohr
69*0b3fd2d3SAndreas Gohr        $this->context->setIsComplete(true);
70*0b3fd2d3SAndreas Gohr        $this->context->setIsAuthenticated((bool) $options['validate']($authzId, $authcId, $password));
71*0b3fd2d3SAndreas Gohr
72*0b3fd2d3SAndreas Gohr        return $this->context;
73*0b3fd2d3SAndreas Gohr    }
74*0b3fd2d3SAndreas Gohr
75*0b3fd2d3SAndreas Gohr    protected function clientProcess(array $options): SaslContext
76*0b3fd2d3SAndreas Gohr    {
77*0b3fd2d3SAndreas Gohr        if (!isset($options['username'])) {
78*0b3fd2d3SAndreas Gohr            throw new SaslException('You must supply a username for the PLAIN mechanism.');
79*0b3fd2d3SAndreas Gohr        }
80*0b3fd2d3SAndreas Gohr        if (!isset($options['password'])) {
81*0b3fd2d3SAndreas Gohr            throw new SaslException('You must supply a password for the PLAIN mechanism.');
82*0b3fd2d3SAndreas Gohr        }
83*0b3fd2d3SAndreas Gohr        $message = new Message([
84*0b3fd2d3SAndreas Gohr            'authzid' => $options['username'],
85*0b3fd2d3SAndreas Gohr            'authcid' => $options['username'],
86*0b3fd2d3SAndreas Gohr            'password' => $options['password'],
87*0b3fd2d3SAndreas Gohr        ]);
88*0b3fd2d3SAndreas Gohr        $this->context->setResponse($this->encoder->encode($message, $this->context));
89*0b3fd2d3SAndreas Gohr        $this->context->setIsComplete(true);
90*0b3fd2d3SAndreas Gohr
91*0b3fd2d3SAndreas Gohr        return $this->context;
92*0b3fd2d3SAndreas Gohr    }
93*0b3fd2d3SAndreas Gohr}
94