TwoFactor.php (phpMyAdmin-5.0.4-english) | : | TwoFactor.php (phpMyAdmin-5.1.0-english) | ||
---|---|---|---|---|
<?php | <?php | |||
/* vim: set expandtab sw=4 ts=4 sts=4: */ | ||||
/** | /** | |||
* Two authentication factor handling | * Two authentication factor handling | |||
* | ||||
* @package PhpMyAdmin | ||||
*/ | */ | |||
declare(strict_types=1); | declare(strict_types=1); | |||
namespace PhpMyAdmin; | namespace PhpMyAdmin; | |||
use PhpMyAdmin\Message; | ||||
use PhpMyAdmin\Plugins\TwoFactor\Application; | use PhpMyAdmin\Plugins\TwoFactor\Application; | |||
use PhpMyAdmin\Plugins\TwoFactor\Invalid; | use PhpMyAdmin\Plugins\TwoFactor\Invalid; | |||
use PhpMyAdmin\Plugins\TwoFactor\Key; | use PhpMyAdmin\Plugins\TwoFactor\Key; | |||
use PhpMyAdmin\Plugins\TwoFactorPlugin; | use PhpMyAdmin\Plugins\TwoFactorPlugin; | |||
use PhpMyAdmin\UserPreferences; | ||||
use PragmaRX\Google2FAQRCode\Google2FA; | use PragmaRX\Google2FAQRCode\Google2FA; | |||
use Samyoul\U2F\U2FServer\U2FServer; | use Samyoul\U2F\U2FServer\U2FServer; | |||
use function array_merge; | ||||
use function class_exists; | ||||
use function in_array; | ||||
use function ucfirst; | ||||
/** | /** | |||
* Two factor authentication wrapper class | * Two factor authentication wrapper class | |||
* | ||||
* @package PhpMyAdmin | ||||
*/ | */ | |||
class TwoFactor | class TwoFactor | |||
{ | { | |||
/** | /** @var string */ | |||
* @var string | ||||
*/ | ||||
public $user; | public $user; | |||
/** | /** @var array */ | |||
* @var array | ||||
*/ | ||||
public $config; | public $config; | |||
/** | /** @var bool */ | |||
* @var boolean | protected $writable; | |||
*/ | ||||
protected $_writable; | ||||
/** | /** @var TwoFactorPlugin */ | |||
* @var TwoFactorPlugin | protected $backend; | |||
*/ | ||||
protected $_backend; | ||||
/** | /** @var array */ | |||
* @var array | protected $available; | |||
*/ | ||||
protected $_available; | ||||
/** | /** @var UserPreferences */ | |||
* @var UserPreferences | ||||
*/ | ||||
private $userPreferences; | private $userPreferences; | |||
/** | /** | |||
* Creates new TwoFactor object | * Creates new TwoFactor object | |||
* | * | |||
* @param string $user User name | * @param string $user User name | |||
*/ | */ | |||
public function __construct($user) | public function __construct($user) | |||
{ | { | |||
/** @var DatabaseInterface $dbi */ | ||||
global $dbi; | global $dbi; | |||
$dbi->initRelationParamsCache(); | $dbi->initRelationParamsCache(); | |||
$this->userPreferences = new UserPreferences(); | $this->userPreferences = new UserPreferences(); | |||
$this->user = $user; | $this->user = $user; | |||
$this->_available = $this->getAvailable(); | $this->available = $this->getAvailableBackends(); | |||
$this->config = $this->readConfig(); | $this->config = $this->readConfig(); | |||
$this->_writable = ($this->config['type'] == 'db'); | $this->writable = ($this->config['type'] === 'db'); | |||
$this->_backend = $this->getBackend(); | $this->backend = $this->getBackendForCurrentUser(); | |||
} | } | |||
/** | /** | |||
* Reads the configuration | * Reads the configuration | |||
* | * | |||
* @return array | * @return array | |||
*/ | */ | |||
public function readConfig() | public function readConfig() | |||
{ | { | |||
$result = []; | $result = []; | |||
skipping to change at line 96 | skipping to change at line 82 | |||
if (isset($config['config_data']['2fa'])) { | if (isset($config['config_data']['2fa'])) { | |||
$result = $config['config_data']['2fa']; | $result = $config['config_data']['2fa']; | |||
} | } | |||
$result['type'] = $config['type']; | $result['type'] = $config['type']; | |||
if (! isset($result['backend'])) { | if (! isset($result['backend'])) { | |||
$result['backend'] = ''; | $result['backend'] = ''; | |||
} | } | |||
if (! isset($result['settings'])) { | if (! isset($result['settings'])) { | |||
$result['settings'] = []; | $result['settings'] = []; | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
public function isWritable(): bool | ||||
{ | ||||
return $this->writable; | ||||
} | ||||
public function getBackend(): TwoFactorPlugin | ||||
{ | ||||
return $this->backend; | ||||
} | ||||
/** | /** | |||
* Get any property of this class | * @return array | |||
* | ||||
* @param string $property name of the property | ||||
* | ||||
* @return mixed|void if property exist, value of the relevant property | ||||
*/ | */ | |||
public function __get($property) | public function getAvailable(): array | |||
{ | { | |||
switch ($property) { | return $this->available; | |||
case 'backend': | } | |||
return $this->_backend; | ||||
case 'available': | public function showSubmit(): bool | |||
return $this->_available; | { | |||
case 'writable': | $backend = $this->backend; | |||
return $this->_writable; | ||||
case 'showSubmit': | return $backend::$showSubmit; | |||
$backend = $this->_backend; | ||||
return $backend::$showSubmit; | ||||
} | ||||
} | } | |||
/** | /** | |||
* Returns list of available backends | * Returns list of available backends | |||
* | * | |||
* @return array | * @return array | |||
*/ | */ | |||
public function getAvailable() | public function getAvailableBackends() | |||
{ | { | |||
$result = []; | $result = []; | |||
if ($GLOBALS['cfg']['DBG']['simple2fa']) { | if ($GLOBALS['cfg']['DBG']['simple2fa']) { | |||
$result[] = 'simple'; | $result[] = 'simple'; | |||
} | } | |||
if (class_exists(Google2FA::class)) { | if (class_exists(Google2FA::class)) { | |||
$result[] = 'application'; | $result[] = 'application'; | |||
} | } | |||
if (class_exists(U2FServer::class)) { | if (class_exists(U2FServer::class)) { | |||
$result[] = 'key'; | $result[] = 'key'; | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
/** | /** | |||
* Returns list of missing dependencies | * Returns list of missing dependencies | |||
* | * | |||
* @return array | * @return array | |||
*/ | */ | |||
public function getMissingDeps() | public function getMissingDeps() | |||
{ | { | |||
skipping to change at line 167 | skipping to change at line 158 | |||
'class' => Application::getName(), | 'class' => Application::getName(), | |||
'dep' => 'bacon/bacon-qr-code', | 'dep' => 'bacon/bacon-qr-code', | |||
]; | ]; | |||
} | } | |||
if (! class_exists(U2FServer::class)) { | if (! class_exists(U2FServer::class)) { | |||
$result[] = [ | $result[] = [ | |||
'class' => Key::getName(), | 'class' => Key::getName(), | |||
'dep' => 'samyoul/u2f-php-server', | 'dep' => 'samyoul/u2f-php-server', | |||
]; | ]; | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
/** | /** | |||
* Returns class name for given name | * Returns class name for given name | |||
* | * | |||
* @param string $name Backend name | * @param string $name Backend name | |||
* | * | |||
* @return string | * @return string | |||
*/ | */ | |||
public function getBackendClass($name) | public function getBackendClass($name) | |||
{ | { | |||
$result = TwoFactorPlugin::class; | $result = TwoFactorPlugin::class; | |||
if (in_array($name, $this->_available)) { | if (in_array($name, $this->available)) { | |||
$result = 'PhpMyAdmin\\Plugins\\TwoFactor\\' . ucfirst($name); | $result = 'PhpMyAdmin\\Plugins\\TwoFactor\\' . ucfirst($name); | |||
} elseif (! empty($name)) { | } elseif (! empty($name)) { | |||
$result = Invalid::class; | $result = Invalid::class; | |||
} | } | |||
return $result; | return $result; | |||
} | } | |||
/** | /** | |||
* Returns backend for current user | * Returns backend for current user | |||
* | * | |||
* @return TwoFactorPlugin | * @return TwoFactorPlugin | |||
*/ | */ | |||
public function getBackend() | public function getBackendForCurrentUser() | |||
{ | { | |||
$name = $this->getBackendClass($this->config['backend']); | $name = $this->getBackendClass($this->config['backend']); | |||
return new $name($this); | return new $name($this); | |||
} | } | |||
/** | /** | |||
* Checks authentication, returns true on success | * Checks authentication, returns true on success | |||
* | * | |||
* @param boolean $skip_session Skip session cache | * @param bool $skip_session Skip session cache | |||
* | * | |||
* @return boolean | * @return bool | |||
*/ | */ | |||
public function check($skip_session = false) | public function check($skip_session = false) | |||
{ | { | |||
if ($skip_session) { | if ($skip_session) { | |||
return $this->_backend->check(); | return $this->backend->check(); | |||
} | } | |||
if (empty($_SESSION['two_factor_check'])) { | if (empty($_SESSION['two_factor_check'])) { | |||
$_SESSION['two_factor_check'] = $this->_backend->check(); | $_SESSION['two_factor_check'] = $this->backend->check(); | |||
} | } | |||
return $_SESSION['two_factor_check']; | return $_SESSION['two_factor_check']; | |||
} | } | |||
/** | /** | |||
* Renders user interface to enter two-factor authentication | * Renders user interface to enter two-factor authentication | |||
* | * | |||
* @return string HTML code | * @return string HTML code | |||
*/ | */ | |||
public function render() | public function render() | |||
{ | { | |||
return $this->_backend->getError() . $this->_backend->render(); | return $this->backend->getError() . $this->backend->render(); | |||
} | } | |||
/** | /** | |||
* Renders user interface to configure two-factor authentication | * Renders user interface to configure two-factor authentication | |||
* | * | |||
* @return string HTML code | * @return string HTML code | |||
*/ | */ | |||
public function setup() | public function setup() | |||
{ | { | |||
return $this->_backend->getError() . $this->_backend->setup(); | return $this->backend->getError() . $this->backend->setup(); | |||
} | } | |||
/** | /** | |||
* Saves current configuration. | * Saves current configuration. | |||
* | * | |||
* @return true|Message | * @return true|Message | |||
*/ | */ | |||
public function save() | public function save() | |||
{ | { | |||
return $this->userPreferences->persistOption('2fa', $this->config, null) ; | return $this->userPreferences->persistOption('2fa', $this->config, null) ; | |||
} | } | |||
/** | /** | |||
* Changes two-factor authentication settings | * Changes two-factor authentication settings | |||
* | * | |||
* The object might stay in partialy changed setup | * The object might stay in partially changed setup | |||
* if configuration fails. | * if configuration fails. | |||
* | * | |||
* @param string $name Backend name | * @param string $name Backend name | |||
* | * | |||
* @return boolean | * @return bool | |||
*/ | */ | |||
public function configure($name) | public function configure($name) | |||
{ | { | |||
$this->config = [ | $this->config = ['backend' => $name]; | |||
'backend' => $name, | ||||
]; | ||||
if ($name === '') { | if ($name === '') { | |||
$cls = $this->getBackendClass($name); | $cls = $this->getBackendClass($name); | |||
$this->config['settings'] = []; | $this->config['settings'] = []; | |||
$this->_backend = new $cls($this); | $this->backend = new $cls($this); | |||
} else { | } else { | |||
if (! in_array($name, $this->_available)) { | if (! in_array($name, $this->available)) { | |||
return false; | return false; | |||
} | } | |||
$cls = $this->getBackendClass($name); | $cls = $this->getBackendClass($name); | |||
$this->config['settings'] = []; | $this->config['settings'] = []; | |||
$this->_backend = new $cls($this); | $this->backend = new $cls($this); | |||
if (! $this->_backend->configure()) { | if (! $this->backend->configure()) { | |||
return false; | return false; | |||
} | } | |||
} | } | |||
$result = $this->save(); | $result = $this->save(); | |||
if ($result !== true) { | if ($result !== true) { | |||
$result->display(); | echo $result->getDisplay(); | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Returns array with all available backends | * Returns array with all available backends | |||
* | * | |||
* @return array | * @return array | |||
*/ | */ | |||
public function getAllBackends() | public function getAllBackends() | |||
{ | { | |||
$all = array_merge([''], $this->available); | $all = array_merge([''], $this->available); | |||
$backends = []; | $backends = []; | |||
foreach ($all as $name) { | foreach ($all as $name) { | |||
$cls = $this->getBackendClass($name); | $cls = $this->getBackendClass($name); | |||
$backends[] = [ | $backends[] = [ | |||
'id' => $cls::$id, | 'id' => $cls::$id, | |||
'name' => $cls::getName(), | 'name' => $cls::getName(), | |||
'description' => $cls::getDescription(), | 'description' => $cls::getDescription(), | |||
]; | ]; | |||
} | } | |||
return $backends; | return $backends; | |||
} | } | |||
} | } | |||
End of changes. 45 change blocks. | ||||
68 lines changed or deleted | 63 lines changed or added |