Closed MobileSkys closed 3 years ago
@MobileSkys I recommend you to set your config in a custom config/users.php file. If you still want to use the code Configure::write('OneTimePasswordAuthenticator.login', true)
, it should be after the plugin bootstrap (Application::pluginBootstrap)
Many thanks @rochamarcelo for your response.
Your First Option -> "I recommend you to set your config in a custom config/users.php file": Understand this option and confirm this does work. :white_check_mark:
Your Second Option -> "should be after the plugin bootstrap": This is our preferred option, as our client requires more control of their application with the functionality to turn 2FA on or off. To achieve this functionality, a boolean value in stored in a database and is maintained via application settings.
We cannot get this option to work Regardless if the database value is used or is set manually (as below) the value seems to be ignored when a user logs-in. :x:
Here is an example of how we have tried to achieve the desired result: Using the following code anywhere in the application (for example AppController.php), it updates Users.php correctly. :white_check_mark:
Configure::write('OneTimePasswordAuthenticator.login', true);
Image below confirms that Users.php is correct prior to login:
<h2>2Factor = <?= Configure::read('OneTimePasswordAuthenticator.login') ?></h2>
After the user adds credentials and logs-in 2FA is ignored. :question:
@MobileSkys for this user case you will need to implement a custom 'checker' logic.
First create a checker based on the default one (\CakeDC\Auth\Authentication\DefaultOneTimePasswordAuthenticationChecker) and overwrite the method isRequired or isEnabled, after this you should update users.php with
'OneTimePasswordAuthenticator.checker' => \App\Authentication\AppOneTimePasswordAuthenticationChecker::class,
'OneTimePasswordAuthenticator.login' => true,
Let me know if this works for you.
Many thanks @rochamarcelo for your help.
This solution uses a dynamic value returned from a database table to switch Two Factor Authentication either ON/OFF.
Create a new file \App\Authentication\AppOneTimePasswordAuthenticationChecker.php as follows
<?php
declare(strict_types=1);
/**
* Copyright 2010 - 2019, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2010 - 2019, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace App\Authentication;
use Cake\Core\Configure;
use Cake\ORM\TableRegistry;
/**
* Default class to check if two factor authentication is enabled and required
*
* @package App\Authentication
*/
class OneTimePasswordAuthenticationChecker implements \CakeDC\Auth\Authentication\OneTimePasswordAuthenticationCheckerInterface
{
/**
* @var string
*/
protected $enabledKey = 'OneTimePasswordAuthenticator.login';
/**
* DefaultTwoFactorAuthenticationChecker constructor.
*
* @param string $enableKey configuration key to check if enabled
*/
public function __construct($enableKey = null)
{
if ($enableKey !== null) {
$this->enabledKey = $enableKey;
}
}
/**
* Check if two factor authentication is enabled
*
* @return bool
*/
public function isEnabled()
{
return Configure::read($this->enabledKey) !== false;
}
/**
* Check if two factor authentication is enabled in database
*
* @return bool
*/
public function checkDatabase()
{
$table = TableRegistry::getTableLocator()->get('Settings');
$two_factor_auth = $table->findByItem('2FA')->toArray();
define('SECURITY_2FA', (boolean)$two_factor_auth[0]['value']);
return SECURITY_2FA;
}
/**
* Check if two factor authentication is required for a user
*
* @param array $user user data
*
* @return bool
*/
public function isRequired(?array $user = null)
{
return !empty($user) && $this->checkDatabase();
}
}
Configure Application.php as follows
public function bootstrap(): void
{
// Call parent to load bootstrap from files.`
parent::bootstrap();`
if (PHP_SAPI === 'cli') {`
$this->bootstrapCli();`
}`
/*
* Only try to load DebugKit in development mode
* Debug Kit should not be installed on a production system
*/
if (Configure::read('debug')) {
Configure::write('DebugKit.panels', ['DebugKit.Packages' => true]);
Configure::write('DebugKit.includeSchemaReflection', true);
$this->addPlugin('DebugKit');
}
// Load more plugins here
//CakeDC Users
Configure::write('Users.config', ['users']);
$this->addPlugin(\CakeDC\Users\Plugin::class);
}
Configure users.php as follows
'OneTimePasswordAuthenticator' => [
'checker' =>\App\Authentication\OneTimePasswordAuthenticationChecker::class,
'login' => true,
'issuer' => null,
// The number of digits the resulting codes will be
'digits' => 6,
// The number of seconds a code will be valid
'period' => 30,
// The algorithm used
'algorithm' => 'sha1',
// QR-code provider (more on this later)
'qrcodeprovider' => null,
// Random Number Generator provider (more on this later)
'rngprovider' => null
],
Just for completeness of this solution here is an example of a input form, edit or create your own:
echo $this->Form->create($settings);
echo $this->Form->hidden('id');
echo $this->Form->hidden('item', ['value' => '2FA']);
echo $this->Form->checkbox('value', ['checked' => SECURITY_2FA]); //Value set in AppOneTimePasswordAuthenticationChecker.php Above
echo $this->Form->button('Update');
echo $this->Form->end();
Versions
Users plugin: 9.0.4 CakePHP: 4.1.5 PHP: 7.4.9
The problem
Trying to change OneTimePasswordAuthenticator.login to TRUE via Application::bootstrap(). I'm using the new release of the CakeDC Users plugin, and followed the documentation to enable one-time password authenticator OneTimePasswordAuthenticator.login appears to be loading the wrong config data.
The 'OneTimePasswordAuthenticator.login' config data when changed, seems to be ignored. Considered solution outlined in #912 without success.
Investigation
users.php
This works as expected when changed manually:
However when using Application::bootstrap() to alter value ... it seems to be ignored.
Application::bootstrap()
Checking OneTimePasswordAuthenticator.login value in various locations throughout application code as follows:
always returns as expected =
TRUE
However when a user is successfully logged in the OneTimePasswordAuthenticator.login is being ignored and treated as FALSE
Observation
Documentation seems to be out of step with the latest code version 9.0.4.