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; 13*0b3fd2d3SAndreas Gohr 14*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Exception\SaslException; 15*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Mechanism\AnonymousMechanism; 16*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Mechanism\CramMD5Mechanism; 17*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Mechanism\DigestMD5Mechanism; 18*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Mechanism\MechanismInterface; 19*0b3fd2d3SAndreas Gohruse FreeDSx\Sasl\Mechanism\PlainMechanism; 20*0b3fd2d3SAndreas Gohr 21*0b3fd2d3SAndreas Gohr/** 22*0b3fd2d3SAndreas Gohr * The main SASL class. 23*0b3fd2d3SAndreas Gohr * 24*0b3fd2d3SAndreas Gohr * @author Chad Sikorra <Chad.Sikorra@gmail.com> 25*0b3fd2d3SAndreas Gohr */ 26*0b3fd2d3SAndreas Gohrclass Sasl 27*0b3fd2d3SAndreas Gohr{ 28*0b3fd2d3SAndreas Gohr /** 29*0b3fd2d3SAndreas Gohr * @var MechanismInterface[] 30*0b3fd2d3SAndreas Gohr */ 31*0b3fd2d3SAndreas Gohr protected $mechanisms = []; 32*0b3fd2d3SAndreas Gohr 33*0b3fd2d3SAndreas Gohr protected $options = [ 34*0b3fd2d3SAndreas Gohr 'supported' => [] 35*0b3fd2d3SAndreas Gohr ]; 36*0b3fd2d3SAndreas Gohr 37*0b3fd2d3SAndreas Gohr public function __construct(array $options = []) 38*0b3fd2d3SAndreas Gohr { 39*0b3fd2d3SAndreas Gohr $this->options = $options + $this->options; 40*0b3fd2d3SAndreas Gohr $this->initMechs(); 41*0b3fd2d3SAndreas Gohr } 42*0b3fd2d3SAndreas Gohr 43*0b3fd2d3SAndreas Gohr /** 44*0b3fd2d3SAndreas Gohr * Get a mechanism object by its name. 45*0b3fd2d3SAndreas Gohr */ 46*0b3fd2d3SAndreas Gohr public function get(string $mechanism): MechanismInterface 47*0b3fd2d3SAndreas Gohr { 48*0b3fd2d3SAndreas Gohr $mech = $this->mechanisms[$mechanism] ?? null; 49*0b3fd2d3SAndreas Gohr 50*0b3fd2d3SAndreas Gohr if ($mech === null) { 51*0b3fd2d3SAndreas Gohr throw new SaslException('The mechanism "%s" is not supported.'); 52*0b3fd2d3SAndreas Gohr } 53*0b3fd2d3SAndreas Gohr 54*0b3fd2d3SAndreas Gohr return $mech; 55*0b3fd2d3SAndreas Gohr } 56*0b3fd2d3SAndreas Gohr 57*0b3fd2d3SAndreas Gohr /** 58*0b3fd2d3SAndreas Gohr * Whether or not the mechanism is supported. 59*0b3fd2d3SAndreas Gohr */ 60*0b3fd2d3SAndreas Gohr public function supports(string $mechanism): bool 61*0b3fd2d3SAndreas Gohr { 62*0b3fd2d3SAndreas Gohr return isset($this->mechanisms()[$mechanism]); 63*0b3fd2d3SAndreas Gohr } 64*0b3fd2d3SAndreas Gohr 65*0b3fd2d3SAndreas Gohr /** 66*0b3fd2d3SAndreas Gohr * Add a mechanism object. 67*0b3fd2d3SAndreas Gohr * 68*0b3fd2d3SAndreas Gohr * @return Sasl 69*0b3fd2d3SAndreas Gohr */ 70*0b3fd2d3SAndreas Gohr public function add(MechanismInterface $mechanism): self 71*0b3fd2d3SAndreas Gohr { 72*0b3fd2d3SAndreas Gohr $this->mechanisms[$mechanism->getName()] = $mechanism; 73*0b3fd2d3SAndreas Gohr 74*0b3fd2d3SAndreas Gohr return $this; 75*0b3fd2d3SAndreas Gohr } 76*0b3fd2d3SAndreas Gohr 77*0b3fd2d3SAndreas Gohr /** 78*0b3fd2d3SAndreas Gohr * Remove a mechanism by its name. 79*0b3fd2d3SAndreas Gohr * 80*0b3fd2d3SAndreas Gohr * @return Sasl 81*0b3fd2d3SAndreas Gohr */ 82*0b3fd2d3SAndreas Gohr public function remove(string $mechanism): self 83*0b3fd2d3SAndreas Gohr { 84*0b3fd2d3SAndreas Gohr if (isset($this->mechanisms[$mechanism])) { 85*0b3fd2d3SAndreas Gohr unset($this->mechanisms[$mechanism]); 86*0b3fd2d3SAndreas Gohr } 87*0b3fd2d3SAndreas Gohr 88*0b3fd2d3SAndreas Gohr return $this; 89*0b3fd2d3SAndreas Gohr } 90*0b3fd2d3SAndreas Gohr 91*0b3fd2d3SAndreas Gohr /** 92*0b3fd2d3SAndreas Gohr * Given an array of mechanism names, and optional options, select the best supported mechanism available. 93*0b3fd2d3SAndreas Gohr * 94*0b3fd2d3SAndreas Gohr * @param string[] $choices array of mechanisms by their name 95*0b3fd2d3SAndreas Gohr * @param array $options array of options (ie. ['use_integrity' => true]) 96*0b3fd2d3SAndreas Gohr * @return MechanismInterface the mechanism selected. 97*0b3fd2d3SAndreas Gohr * @throws SaslException if no supported mechanism could be found. 98*0b3fd2d3SAndreas Gohr */ 99*0b3fd2d3SAndreas Gohr public function select(array $choices = [], array $options = []): MechanismInterface 100*0b3fd2d3SAndreas Gohr { 101*0b3fd2d3SAndreas Gohr $selector = new MechanismSelector($this->mechanisms()); 102*0b3fd2d3SAndreas Gohr 103*0b3fd2d3SAndreas Gohr return $selector->select($choices, $options); 104*0b3fd2d3SAndreas Gohr } 105*0b3fd2d3SAndreas Gohr 106*0b3fd2d3SAndreas Gohr /** 107*0b3fd2d3SAndreas Gohr * @return MechanismInterface[] 108*0b3fd2d3SAndreas Gohr */ 109*0b3fd2d3SAndreas Gohr public function mechanisms(): array 110*0b3fd2d3SAndreas Gohr { 111*0b3fd2d3SAndreas Gohr return $this->mechanisms; 112*0b3fd2d3SAndreas Gohr } 113*0b3fd2d3SAndreas Gohr 114*0b3fd2d3SAndreas Gohr protected function initMechs(): void 115*0b3fd2d3SAndreas Gohr { 116*0b3fd2d3SAndreas Gohr $this->mechanisms = [ 117*0b3fd2d3SAndreas Gohr DigestMD5Mechanism::NAME => new DigestMD5Mechanism(), 118*0b3fd2d3SAndreas Gohr CramMD5Mechanism::NAME => new CramMD5Mechanism(), 119*0b3fd2d3SAndreas Gohr PlainMechanism::NAME => new PlainMechanism(), 120*0b3fd2d3SAndreas Gohr AnonymousMechanism::NAME => new AnonymousMechanism(), 121*0b3fd2d3SAndreas Gohr ]; 122*0b3fd2d3SAndreas Gohr 123*0b3fd2d3SAndreas Gohr if (is_array($this->options['supported']) && !empty($this->options['supported'])) { 124*0b3fd2d3SAndreas Gohr foreach (array_keys($this->mechanisms) as $mechName) { 125*0b3fd2d3SAndreas Gohr if (!in_array($mechName, $this->options['supported'], true)) { 126*0b3fd2d3SAndreas Gohr unset($this->mechanisms[$mechName]); 127*0b3fd2d3SAndreas Gohr } 128*0b3fd2d3SAndreas Gohr } 129*0b3fd2d3SAndreas Gohr } 130*0b3fd2d3SAndreas Gohr } 131*0b3fd2d3SAndreas Gohr} 132