"Fossies" - the Fresh Open Source Software Archive

Member "phpMyAdmin-5.1.0-all-languages/libraries/classes/TwoFactor.php" (24 Feb 2021, 6968 Bytes) of package /linux/www/phpMyAdmin-5.1.0-all-languages.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "TwoFactor.php": 5.0.4-english_vs_5.1.0-english.

    1 <?php
    2 /**
    3  * Two authentication factor handling
    4  */
    5 
    6 declare(strict_types=1);
    7 
    8 namespace PhpMyAdmin;
    9 
   10 use PhpMyAdmin\Plugins\TwoFactor\Application;
   11 use PhpMyAdmin\Plugins\TwoFactor\Invalid;
   12 use PhpMyAdmin\Plugins\TwoFactor\Key;
   13 use PhpMyAdmin\Plugins\TwoFactorPlugin;
   14 use PragmaRX\Google2FAQRCode\Google2FA;
   15 use Samyoul\U2F\U2FServer\U2FServer;
   16 use function array_merge;
   17 use function class_exists;
   18 use function in_array;
   19 use function ucfirst;
   20 
   21 /**
   22  * Two factor authentication wrapper class
   23  */
   24 class TwoFactor
   25 {
   26     /** @var string */
   27     public $user;
   28 
   29     /** @var array */
   30     public $config;
   31 
   32     /** @var bool */
   33     protected $writable;
   34 
   35     /** @var TwoFactorPlugin */
   36     protected $backend;
   37 
   38     /** @var array */
   39     protected $available;
   40 
   41     /** @var UserPreferences */
   42     private $userPreferences;
   43 
   44     /**
   45      * Creates new TwoFactor object
   46      *
   47      * @param string $user User name
   48      */
   49     public function __construct($user)
   50     {
   51         global $dbi;
   52 
   53         $dbi->initRelationParamsCache();
   54 
   55         $this->userPreferences = new UserPreferences();
   56         $this->user = $user;
   57         $this->available = $this->getAvailableBackends();
   58         $this->config = $this->readConfig();
   59         $this->writable = ($this->config['type'] === 'db');
   60         $this->backend = $this->getBackendForCurrentUser();
   61     }
   62 
   63     /**
   64      * Reads the configuration
   65      *
   66      * @return array
   67      */
   68     public function readConfig()
   69     {
   70         $result = [];
   71         $config = $this->userPreferences->load();
   72         if (isset($config['config_data']['2fa'])) {
   73             $result = $config['config_data']['2fa'];
   74         }
   75         $result['type'] = $config['type'];
   76         if (! isset($result['backend'])) {
   77             $result['backend'] = '';
   78         }
   79         if (! isset($result['settings'])) {
   80             $result['settings'] = [];
   81         }
   82 
   83         return $result;
   84     }
   85 
   86     public function isWritable(): bool
   87     {
   88         return $this->writable;
   89     }
   90 
   91     public function getBackend(): TwoFactorPlugin
   92     {
   93         return $this->backend;
   94     }
   95 
   96     /**
   97      * @return array
   98      */
   99     public function getAvailable(): array
  100     {
  101         return $this->available;
  102     }
  103 
  104     public function showSubmit(): bool
  105     {
  106         $backend = $this->backend;
  107 
  108         return $backend::$showSubmit;
  109     }
  110 
  111     /**
  112      * Returns list of available backends
  113      *
  114      * @return array
  115      */
  116     public function getAvailableBackends()
  117     {
  118         $result = [];
  119         if ($GLOBALS['cfg']['DBG']['simple2fa']) {
  120             $result[] = 'simple';
  121         }
  122         if (class_exists(Google2FA::class)) {
  123             $result[] = 'application';
  124         }
  125         if (class_exists(U2FServer::class)) {
  126             $result[] = 'key';
  127         }
  128 
  129         return $result;
  130     }
  131 
  132     /**
  133      * Returns list of missing dependencies
  134      *
  135      * @return array
  136      */
  137     public function getMissingDeps()
  138     {
  139         $result = [];
  140         if (! class_exists(Google2FA::class)) {
  141             $result[] = [
  142                 'class' => Application::getName(),
  143                 'dep' => 'pragmarx/google2fa-qrcode',
  144             ];
  145         }
  146         if (! class_exists('BaconQrCode\Renderer\Image\Png')) {
  147             $result[] = [
  148                 'class' => Application::getName(),
  149                 'dep' => 'bacon/bacon-qr-code',
  150             ];
  151         }
  152         if (! class_exists(U2FServer::class)) {
  153             $result[] = [
  154                 'class' => Key::getName(),
  155                 'dep' => 'samyoul/u2f-php-server',
  156             ];
  157         }
  158 
  159         return $result;
  160     }
  161 
  162     /**
  163      * Returns class name for given name
  164      *
  165      * @param string $name Backend name
  166      *
  167      * @return string
  168      */
  169     public function getBackendClass($name)
  170     {
  171         $result = TwoFactorPlugin::class;
  172         if (in_array($name, $this->available)) {
  173             $result = 'PhpMyAdmin\\Plugins\\TwoFactor\\' . ucfirst($name);
  174         } elseif (! empty($name)) {
  175             $result = Invalid::class;
  176         }
  177 
  178         return $result;
  179     }
  180 
  181     /**
  182      * Returns backend for current user
  183      *
  184      * @return TwoFactorPlugin
  185      */
  186     public function getBackendForCurrentUser()
  187     {
  188         $name = $this->getBackendClass($this->config['backend']);
  189 
  190         return new $name($this);
  191     }
  192 
  193     /**
  194      * Checks authentication, returns true on success
  195      *
  196      * @param bool $skip_session Skip session cache
  197      *
  198      * @return bool
  199      */
  200     public function check($skip_session = false)
  201     {
  202         if ($skip_session) {
  203             return $this->backend->check();
  204         }
  205         if (empty($_SESSION['two_factor_check'])) {
  206             $_SESSION['two_factor_check'] = $this->backend->check();
  207         }
  208 
  209         return $_SESSION['two_factor_check'];
  210     }
  211 
  212     /**
  213      * Renders user interface to enter two-factor authentication
  214      *
  215      * @return string HTML code
  216      */
  217     public function render()
  218     {
  219         return $this->backend->getError() . $this->backend->render();
  220     }
  221 
  222     /**
  223      * Renders user interface to configure two-factor authentication
  224      *
  225      * @return string HTML code
  226      */
  227     public function setup()
  228     {
  229         return $this->backend->getError() . $this->backend->setup();
  230     }
  231 
  232     /**
  233      * Saves current configuration.
  234      *
  235      * @return true|Message
  236      */
  237     public function save()
  238     {
  239         return $this->userPreferences->persistOption('2fa', $this->config, null);
  240     }
  241 
  242     /**
  243      * Changes two-factor authentication settings
  244      *
  245      * The object might stay in partially changed setup
  246      * if configuration fails.
  247      *
  248      * @param string $name Backend name
  249      *
  250      * @return bool
  251      */
  252     public function configure($name)
  253     {
  254         $this->config = ['backend' => $name];
  255         if ($name === '') {
  256             $cls = $this->getBackendClass($name);
  257             $this->config['settings'] = [];
  258             $this->backend = new $cls($this);
  259         } else {
  260             if (! in_array($name, $this->available)) {
  261                 return false;
  262             }
  263             $cls = $this->getBackendClass($name);
  264             $this->config['settings'] = [];
  265             $this->backend = new $cls($this);
  266             if (! $this->backend->configure()) {
  267                 return false;
  268             }
  269         }
  270         $result = $this->save();
  271         if ($result !== true) {
  272             echo $result->getDisplay();
  273         }
  274 
  275         return true;
  276     }
  277 
  278     /**
  279      * Returns array with all available backends
  280      *
  281      * @return array
  282      */
  283     public function getAllBackends()
  284     {
  285         $all = array_merge([''], $this->available);
  286         $backends = [];
  287         foreach ($all as $name) {
  288             $cls = $this->getBackendClass($name);
  289             $backends[] = [
  290                 'id' => $cls::$id,
  291                 'name' => $cls::getName(),
  292                 'description' => $cls::getDescription(),
  293             ];
  294         }
  295 
  296         return $backends;
  297     }
  298 }