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