Trying to get Laravel Dusk to behave with sqlite database - testing

I'm trying to get Laravel Dusk to play nicely with an App i'm trying to test.
At the moment I can write to a test sqlite database but when I try to test a login form following the guidance it appears the details in the development database are being used instead.
Here's my test:
class LoginTest extends DuskTestCase
{
private $user;
use DatabaseMigrations;
public function setUp()
{
parent::setUp();
$this->user = factory(User::class)->create(['password' => bcrypt('secret')]);
}
/**
* A Dusk test example.
*
* #return void
* #throws \Exception
* #throws \Throwable
*/
public function test_user_can_log_in()
{
$this->browse(function (Browser $browser) {
$browser->visit('/login')
->assertSee('Members sign in')
->type('email', $this->user->email)
->type('password', 'secret')
->driver->executeScript('window.scrollTo(0, 500);');
$browser->press('Sign in')
->assertPathIs('/home');
});
}
}
This test fails authentication as the user I've just created doesn't exist in the development Mysql database it is reading from.
I am able to see the user I've just created in the sqlite database and can query that user exists
What am I doing wrong? Does Laravel Auth do something to override the connections?
Thank you
edit
Here is my .env file
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=backend_cms
DB_USERNAME=homestead
DB_PASSWORD=secret
DB_DATABASE_2=members
DB_USERNAME_2=homestead
DB_PASSWORD_2=secret
and my .env.dusk.local (I've also tried renaming to just .env.dusk but no change.
DB_CONNECTION=sqlite_testing
DUSK=true
I read that only the items you need changing should be there so assumed only the connection required?
edit
Here's the config entries in database.php
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
],
'sqlite_testing_memory' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'sqlite_testing' => [
'driver' => 'sqlite',
'database' => database_path('database.sqlite'),
'prefix' => '',
],

Related

Laminas Config Module Routing

I have started the latest tutorial for Laminas.
The routing for a new module called Provider is not working
A 404 error occurred
Page not found.
The requested URL could not be matched by routing.
on looking at my Module.php code I see:
getConfig() is not called but
getServiceConfig() and getControllerConfig() are.
getConfig in the Application module is not called either
<?php
namespace Provider;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Db\ResultSet\ResultSet;
use Laminas\Db\TableGateway\TableGateway;
use Laminas\ModuleManager\Feature\AutoloaderProviderInterface;
use Laminas\ModuleManager\Feature\ConfigProviderInterface;
class Module implements ConfigProviderInterface, AutoloaderProviderInterface
{
public function getConfig()
{
die ("getConfig");
return include __DIR__ . '/../config/module.config.php';
}
public function getAutoloaderConfig()
{
//die ("getAutoloaderConfig");
//return array(
// 'Laminas\Loader\StandardAutoloader' => array(
// 'namespaces' => array(
// __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
// ),
// ),
//);
}
public function getServiceConfig()
{
//die ("getServiceConfig");
return [
'factories' => [
Model\ProviderTable::class => function($container) {
$tableGateway = $container->get(Provider\ProviderTableGateway::class);
return new Model\ProviderTable($tableGateway);
},
Model\ProviderTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Model\Album());
return new TableGateway('provider', $dbAdapter, null, $resultSetPrototype);
},
],
];
}
public function getControllerConfig()
{
//die ("getControllerConfig");
return [
'factories' => [
Controller\ProviderController::class => function($container) {
return new Controller\ProviderController(
$container->get(Model\ProviderTable::class)
);
},
],
];
}
}
You need to enable development mode. run composer development-enable to active development mode.
Maybe the composer json is not updated (my-application/composer.json)
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/",
"Provider\\": "module/Provider/src/"
}
},
Update autoload classmap:
composer dump-autoload
https://docs.laminas.dev/tutorials/getting-started/modules/#autoloading
Have you added router configuration?
In your attached code above you have the following function :
public function getConfig()
{
//die ("getConfig"); // BE SURE YOU REMOVE THIS LINE
return include __DIR__ . '/../config/module.config.php';
}
it's include file for additional settings. in this file "/../config/module.config.php" you should add your router configuration. It should look like this:
return [
//... other setting
'router' => [
'routes' => [
// Literal route named "home"
'home' => [
'type' => 'literal',
'options' => [
'route' => '/',
'defaults' => [
'controller' => 'Application\Controller\IndexController',
'action' => 'index',
],
],
],
// Literal route named "contact"
'contact' => [
'type' => 'literal',
'options' => [
'route' => 'contact',
'defaults' => [
'controller' => 'Application\Controller\ContactController',
'action' => 'form',
],
],
],
],
],
];
more reading can be found https://docs.laminas.dev/laminas-router/routing/#simple-example-with-two-literal-routes
As mentioned before any time you add a custom module you will need to add an entry for the autoloader in composer.json and run the dump-autoload. You will also need to add an entry in the root level /config/modules.config.php file. Is there currently an entry for Application? If memory serves and your working from the examples the last two should be Application, then Album. Verify those are there and that the application is in development mode. You can check the current mode with "composer development-status". Just check composer.json in the top level and look for the "scripts" entry. The key is the command to pass to composer.
Also, be mindful of using the interfaces when configuring the application in the Module class. The Module feature methods are reserved for closures as they will not be cached when you disable development mode. Instead use the corresponding service manager array keys. that can be found here:
Service manager config:
https://docs.laminas.dev/laminas-servicemanager/configuring-the-service-manager/
Corresponding module manager feature config:
https://docs.laminas.dev/laminas-modulemanager/module-manager/
I suppose its worth mentioning that most if not all of the Feature interface methods map directly to a default pluginmanager implementation, ergo a specialized service manager.

Magento2 module fields still visible in admin after module is disabled

I am experiencing an issue while trying to disable a Magento2 module causing custom values to still be visible in the customer edit page.
I would like to know what i have to do to completely get rid of a module and its data from a Magento2 system.
Magento version: 2.3.2
PHP version: 7.2.19
A custom(own) Magento2 module was installed by:
Copying code: app/code/VENDOR/MODULE
Running: magento module:enable VENDOR_MODULE
Running magento setup:upgrade
This module creates a couple of Customer EAV attributes that correctly show in the customer edit form.
I am able to populate/save/update values successfully.
I am disabling the module as such:
Running: magento module:disable VENDOR_MODULE
Running magento setup:upgrade
Completely removing the app/code/VENDOR/MODULE directory
When i navigate back to the customer edit page i can still see the attributes, visible and populated with previously entered data.
At this point i have tried the following:
Manually removing the entry in setup_module.
Including a Uninstall class.
A combination of magento cache:clean && magento setup:di:compile.
Classes attached:
InstallData.php
namespace VENDOR\MODULE\Setup;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Customer\Model\Customer;
use Magento\Customer\Setup\CustomerSetupFactory;
class InstallData implements InstallDataInterface {
private $customerSetupFactory;
/**
* Constructor
*
* #param \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory
*/
public function __construct(CustomerSetupFactory $customerSetupFactory) {
$this->customerSetupFactory = $customerSetupFactory;
}
/**
* {#inheritdoc}
*/
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {
$this->installModule1($setup, $context);
$this->installModule2($setup, $context);
}
private function installModule1(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
$customerSetup->addAttribute(\Magento\Customer\Model\Customer::ENTITY, 'module1', [
'type' => 'varchar',
'label' => 'Module1 label',
'input' => 'text',
'source' => '',
'required' => false,
'visible' => true,
'position' => 500,
'system' => false,
'backend' => ''
]);
$attribute = $customerSetup->getEavConfig()->getAttribute('customer', 'module1')
->addData(['used_in_forms' => [
'adminhtml_customer',
'adminhtml_checkout',
'customer_account_create',
'customer_account_edit'
]
]);
$attribute->save();
}
private function installModule1(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
$customerSetup->addAttribute(\Magento\Customer\Model\Customer::ENTITY, 'module2', [
'type' => 'varchar',
'label' => 'Module2 label',
'input' => 'text',
'source' => '',
'required' => false,
'visible' => true,
'position' => 500,
'system' => false,
'backend' => ''
]);
$attribute = $customerSetup->getEavConfig()->getAttribute('customer', 'module2')
->addData(['used_in_forms' => [
'adminhtml_customer',
'adminhtml_checkout',
'customer_account_create',
'customer_account_edit'
]
]);
$attribute->save();
}
}
Uninstall.php
namespace VENDOR\MODULE\Setup;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Db\Select;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\UninstallInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
class Uninstall implements UninstallInterface {
private $_eavSetupFactory;
private $_mDSetup;
public function __construct(EavSetupFactory $eavSetupFactory, ModuleDataSetupInterface $mDSetup) {
$this->_eavSetupFactory = $eavSetupFactory;
$this->_mDSetup = $mDSetup;
}
public function uninstall(SchemaSetupInterface $setup, ModuleContextInterface $context) {
$installer = $setup;
$eavSetup = $this->_eavSetupFactory->create(['setup' => $this->_mDSetup]);
$eavSetup->removeAttribute(\Magento\Catalog\Model\Customer::ENTITY, 'module1');
$eavSetup->removeAttribute(\Magento\Catalog\Model\Customer::ENTITY, 'module2');
}
}
For Customer attributes you need to delete the specific attributes entry from table "eav_attribute" you can search by "attribute_code" and delete that row, you have to delete attributes from the database because there is no functionality in admin to delete an attribute
This is the method by which the custom attribute can be removed as I also tried manually to delete that module attribute and it took more than 1 day to find this solution.
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
$eavSetup->removeAttribute(Customer::ENTITY, "<attribute name>");
}
You can remove multiple attribute too at same time by separating attribute name by commas.
After this just run -
bin/magento setup:upgrade && bin/magento setup:static-content:deploy -f

Laravel 5.3 Auth Session Not Working

I did the Laravel update from 5.2 to 5.3 and when I put it on the server came the surprise, the sessions were not working ...
I already tried to do some things, but all to no avail ....
Web routes file
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('auth/facebook', 'SocialAuthController#redirect');
Route::get('auth/facebook/callback', 'SocialAuthController#handleProviderCallback');
Authentication file
/**
* Obtain the user information from Facebook.
*
* #return Response
*/
public function handleProviderCallback()
{
$user = Socialite::driver('facebook')->user();
$authUser = $this->findOrCreateUser($user);
$id = $authUser['id'];
$email = $authUser['email'];
$password = $authUser['senha'];
$credentials = array('email' => $email, 'password' => $password, 'excluded' => 0);
Auth::attempt($credentials);
Auth::loginUsingId($id);
If i run dd( Auth::user() ); the auth is working, but after the redirect the session is lose
Kernel file
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
To fix this i change the file session.php
Look for
'cookie' => 'laravel_session'
And change to
'cookie' => 'app_session',
After it every works fine
The answer below is not working.
When I upgraded to version 5.3 I needed to move the routes file and found that I needed to remove the web middleware line and this problem started ...
I just readjusted the line and it's working now.
Route::group(['middleware' => ['web']], function () {
Route::get('auth/facebook', 'SocialAuthController#redirect');
Route::get('auth/facebook/callback', 'SocialAuthController#handleProviderCallback');

ZF2 / doctrine ORM authentication different Entity

in my application (ZF2 / ORM) i have 3 Entities (with Single Table inheritance)
User
Owner extends User
Agent extends User
i want to make one single Authentication (Login) for the 3 Entity using
doctrine.authenticationservice.orm_default
module.config.php
//other doctrine config
'authentication' => array(
'orm_default' => array(
'object_manager' => 'Doctrine\ORM\EntityManager',
'identity_class' => 'Application\Entity\User',
'identity_property' => 'email',
'credential_property' => 'password',
'credential_callable' => function(User $user, $passwordGiven) {
return $user->getPassword() == md5($passwordGiven);
},
),
),
and the process of login
//LoginController.php
// ..data validation
$this->authService = $this->getServiceLocator()->get('doctrine.authenticationservice.orm_default');
$AuthAdapter = $this->authService->getAdapter();
$AuthAdapter->setIdentity($this->request->getPost('email'));
$AuthAdapter->setCredential(md5($this->request->getPost('password')));
$result = $this->authService->authenticate();
if($result->isValid()){
$identity = $result->getIdentity();
//continue
}
how can i do this process without caring about object type,
when i try to login with email of an Agent, i get this error
Catchable fatal error: Argument 1 passed to Application\Module::{closure}() must be an instance of User, instance of Application\Entity\Owner given
The error you mention is due to the type hint on:
function(User $user) {
Which leads me to believe that you have a missing namespace declaration in your config file; in which case you can either add it or use the FQCN.
function(\Application\Entity\User $user) {
Nevertheless, I don't think it's actually the problem. You can only define one 'identity_class' with doctrine authentication (which the adapter will use to load the entity from the entity manager). If you have multiple entity classes there is no way to have each of these tested with one adapter.
However, the configuration is really just creating a new authentication adapter, specifically DoctrineModule\Authentication\Adapter\ObjectRepository. One solution would be to create multiple ObjectRepository adapters, each with the correct configuration for the different entities and then loop through each of them while calling authenticate() on the Zend\Authentication\AuthenticationService.
For example :
public function methodUsedToAutheticate($username, $password)
{
// Assume we have an array of configured adapters in an array
foreach($adapters as $adapter) {
$adapter->setIdentity($username);
$adapter->setCredential($password);
// Authenticate using the new adapter
$result = $authService->authenticate($adapter);
if ($result->isValid()) {
// auth success
break;
}
}
return $result; // auth failed
}
As previously mentioned is the doctrine config will not allow for more than one adapter, so you would need to create them manually and remove your current configuration.
Another example
public function getServiceConfig()
{
return [
'factories' => [
'MyServiceThatDoesTheAuthetication' => function($sm) {
$service = new MyServiceThatDoesTheAuthetication();
// Assume some kind of api to add multiple adapters
$service->addAuthAdapter($sm->get('AuthAdapterUser'));
$service->addAuthAdapter($sm->get('AuthAdapterOwner'));
$service->addAuthAdapter($sm->get('AuthAdapterAgent'));
return $service;
},
'AuthAdapterAgent' => function($sm) {
return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
'object_manager' => $sm->get('ObjectManager'),
'identity_class' => 'Application\Entity\Agent',
'identity_property' => 'email',
'credential_property' => 'password'
));
},
'AuthAdapterOwner' => function($sm) {
return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
'object_manager' => $sm->get('ObjectManager'),
'identity_class' => 'Application\Entity\Owner',
'identity_property' => 'email',
'credential_property' => 'password'
));
},
// etc...
],
];
}
Hopefully this gives you some ideas as to what is required.
Lastly, if you would consider other modules, ZfcUser already has a 'chainable adapter' which actually does the above (but uses the event manager) so It might be worth taking a look at even if you don't use it.

CakePHP 2, how to AuthComponent::login() with plain-text password?

I would like to implement CakePHP 2 website over existing database with plain-text password field.
This is my AppController
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
'logoutRedirect' => array('controller' => 'users', 'action' => 'home'),
'authError' => 'You cannot view this page',
'authorize' => array('Controller'),
'authenticate' => array(
'Form' => array(
'userModel' => 'User',
'fields' => array('username' => 'user_id', 'password' => 'user_password')
)
)
)
);
public function isAuthorized($user) {
return true;
}
function beforeFilter() {
$this->Auth->allow('home');
//$this->Auth->authenticate = $this->User;
parent::beforeFilter();
}
This is my UserController.
class UsersController extends AppController {
public $paginate = array(
'fields' => array('user_id', 'user_desc', 'user_password'),
'limit' => 25,
'order' => array(
'user_id' => 'asc'
)
);
function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Cannot Login');
}
}
}
}
This is my User model
class User extends AppModel {
public $name = 'User';
public $primaryKey = 'user_id';
public $belongsTo = 'Group';
}
According to those files above, when I pressed the Login button on login.ctp, I saw
select * from users where user_password = 'this_is_hashing_password'
on the sql dump section.
So, how to turn-off the automatic hashing algorithm, so the login() will compare the user input to the database stored password as plain-text???
I have tried lots of reading on the CakePHP book but I cannot find any, also using hashPasswords($data) technique which found from the internet is not working.
Please help.
Kongthap.
The best answer really is to batch-process your stored passwords so they are hashed, however there are cases where you may be adding a Cake app to an existing application that hashes passwords differently (say by not hashing them at all), so the question is valid even if the goal in this case is not.
Try these resources for modifying Cake's password hashing function, depending on your Cake version:
Cake 2.x
Cake 1.3
I got plain text password working in Cakephp 3, this should only be use for DEVELOPMENT purpose, you should never store password in plain text in production.
That being said, during development, plain text password allows me to focus on login instead of implementing a fully functional user encrypt/decrypt logic. Which is going to be replaced by an OAuth / SAML module anyway...
OK here comes the source code:
ROOT/src/Auth/PlainTextPasswordHasher.php
<?php
namespace App\Auth;
use Cake\Auth\AbstractPasswordHasher;
/**
* Plain text password for demo use, DO NOT PUSTH THIS TO PROD
*/
class PlainTextPasswordHasher extends AbstractPasswordHasher
{
public function hash($password)
{
return $password;
}
public function check($password, $hashedPassword)
{
return $password === $hashedPassword;
}
}
ROOT/src/Controller/PagesController.php
<?php
class PagesController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'passwordHasher' => [
'className' => 'PlainText',
],
'userModel' => 'YourUsers',
]
],
'loginAction' => [
'controller' => 'Logins',
'action' => 'login'
]
]);
}
}
Source: This video https://www.youtube.com/watch?v=eASSNS1f3V4 and this section of the official doc: https://book.cakephp.org/3.0/en/controllers/components/authentication.html#creating-custom-password-hasher-classes