I try make test with authentication fosuserbundle, but still is fail, i find solution for symfony 2.3 but it doesn't works
https://gist.github.com/deltaepsilon/6391565
i also try create client by two funcitons
protected function createAuthorizedClient2()
{
$client = static::createClient();
$container = $client->getContainer();
$session = $container->get('session');
/** #var $userManager \FOS\UserBundle\Doctrine\UserManager */
$userManager = $container->get('fos_user.user_manager');
/** #var $loginManager \FOS\UserBundle\Security\LoginManager */
$loginManager = $container->get('fos_user.security.login_manager');
$firewallName = $container->getParameter('fos_user.firewall_name');
$user = $userManager->findUserBy(array('username' => 'admin'));
$loginManager->loginUser($firewallName, $user);
// save the login token into the session and put it in a cookie
$container->get('session')->set('_security_' . $firewallName, serialize($container->get('security.context')->getToken()));
$container->get('session')->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
return $client;
}
protected function createAuthorizedClient()
{
$client = static::createClient();
$container = static::$kernel->getContainer();
$session = $container->get('session');
$person = self::$kernel->getContainer()->get('doctrine')->getRepository('BergUserDataBundle:UserLogin')->findOneByUsername('admin');
$token = new UsernamePasswordToken($person, null, 'main', $person->getRoles());
$session->set('_security_main', serialize($token));
$session->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
return $client;
}
This is no longer the recommended way of testing with an authenticated client.
The new recommended way is much simpler - to submit plain old HTTP credentials and then tell your test environment firewall to authenticate via this method instead of the FOS User Provider.
See http://symfony.com/doc/current/cookbook/testing/http_authentication.html
Related
I am using Symfony Panther for some testing.
When I want to log a User like this :
protected function setUpPanther()
{
$client = static::createPantherClient(['readinessPath' => '/error']);
$client->manage()->window()->maximize();
$this->client = $client;
}
protected function loginPantherClient(Client $client, User $user)
{
$client->request('GET', '/error');
$session = self::$container->get('session');
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$session->set('_security_main', serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);
}
public function testUpdateProductDetails()
{
$this->setUpPanther();
$admin = $this->getSuperAdminAccount();
$this->loginPantherClient($this->client, $admin);
$this->client->request('GET', '/');
$this->assertSelectorExists('div.form-group');
}
A strange phenomenon occurs.
My client goes to the error page to initialize the cookie (required)
And here I have the impression that the authentication of my client is not taken into account, because if you look closely, in my test, I then make a request on
$this->client->request('GET', '/');
But instead of redirecting me to the requested page, it redirects me to / login, as if during the request, the user was not authenticated, and therefore, was redirected to the login page, while in my code, I authenticate the user before
Has someone already had this problem ?
Try to return client from loginPantherClient function:
protected function loginPantherClient(Client $client, User $user)
{
$client->request('GET', '/error');
$session = self::$container->get('session');
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$session->set('_security_main', serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);
return $client;
}
public function testUpdateProductDetails()
{
$this->setUpPanther();
$admin = $this->getSuperAdminAccount();
$this->client = $this->loginPantherClient($this->client, $admin);
$this->client->request('GET', '/');
$this->assertSelectorExists('div.form-group');
}
or remove from loginPantherClient function $client argument:
protected function loginPantherClient(User $user)
{
$this->client->request('GET', '/error');
$session = self::$container->get('session');
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$session->set('_security_main', serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$this->client->getCookieJar()->set($cookie);
}
public function testUpdateProductDetails()
{
$this->setUpPanther();
$admin = $this->getSuperAdminAccount();
$this->loginPantherClient($admin);
$this->client->request('GET', '/');
$this->assertSelectorExists('div.form-group');
}
I'm creating functionnal tests on a Symfony 3.4 application.
<?php
namespace AppBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\HttpFoundation\Response;
class UserControllerTest extends WebTestCase
{
/**
* Connect to the website while being logged in
* Logs in with (admin, password : a)
*/
public function connection()
{
$client = static::createClient();
$container = static::$kernel->getContainer();
$session = $container->get('session');
// Get the user (has to exist in the database)
$person = self::$kernel->getContainer()->get('doctrine')->getRepository('AppBundle:User')->findOneByUsername('admin');
$token = new UsernamePasswordToken($person, null, 'main', $person->getRoles());
$session->set('_security_main', serialize($token));
$session->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
// Return the client
return $client;
}
public function accessEditPage()
{
$client = $this->connection();
$crawler = $client->request('GET', '/user/');
$this->assertSame(Response::HTTP_OK, $client->getResponse()->getStatusCode());
$this->assertContains(
'Liste des utilisateurices',
$client->getResponse()->getContent()
);
// Select the button of the user created for the test
// Wont work if there are already more than 10 users in the database
$link = $crawler
->filter('tr > td > a:contains("")')
->last()
->link()
;
$crawler = $client->click($link);
return array($client,$crawler);
}
/**
* Create a new user
*/
public function testCreate()
{
$client = $this->connection();
$crawler = $client->request('GET', '/user/new');
$this->assertSame(Response::HTTP_OK, $client->getResponse()->getStatusCode());
// Vérifie si la page affiche le bon texte
$this->assertContains(
'Enregistrer',
$client->getResponse()->getContent()
);
// Select the form and fill its values
$form = $crawler->selectButton(' Créer')->form();
$values = $form->getPhpValues();
$values['appbundle_user']['username'] = 'Jean';
$values['appbundle_user']['plainPassword']['first'] = 'motdepasse';
$values['appbundle_user']['plainPassword']['second'] = 'motdepasse';
$crawler = $client->request($form->getMethod(), $form->getUri(), $values,$form->getPhpFiles());
$crawler = $client->followRedirect();
$this->assertContains(
'Jean',
$client->getResponse()->getContent()
);
}
}
Currently, my Controller tests create databases entries and depends on existing ones and that's a problem.
I want to mock the repositories used in the controller to avoid creating entries when I test my controllers but I haven't found helpful documentation about it. As I can't find documentation, I also wonder if what I want to do is a good practice or not.
Accoring to documentation I'm trying to mock session in my PHPUnit test:
public function testAction()
{
$session = new Session(new MockArraySessionStorage());
$session->set('abc', 'xyz');
$client = static::createClient();
$client->getContainer()->set('session', $session);
$client->request('GET', '/');
}
And in my controller I trying to get session value:
public function mainAction()
{
$session = $this->get('session');
var_dump($session->get('abc'), $session->all());die; //returns null and []
}
Why this stuff doesn't work?
I believe it's because the session is resolved with the cookie, and you don't set the cookie who link the session to the client.
You should add:
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
There is a full example to log in a user:
$session = $this->_container->get('session');
$user = $this->_em->getRepository('UserBundle:User')
->findOneByEmail($email);
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$session->set('_security_<security_context>', serialize($token));
$session->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
Hope it help
I am currently working on unit testing my symfony 2.8 based admin area.
So I wrote a small basic test for the dashboard: The tests checks that
a) If the user is currently not logged in, there should be a redirect to the login page.
b) If the user is logged in, the dashboard should be shown.
In order to "log in" the user ( = to create an active session) I came up with a small helper function that is based on the respective cookbook article from the symfony documentation: How to Simulate Authentication with a Token in a Functional Test
This however does not seem to work. My initial tests fails. So I have added another request to a dummy controller that only prints out session information. This shows that while the seems to be set correctly, the current user information and the security token storage seem to be incorrect - as I get the default "AnonymousToken" and a null return from the getUser method.
Here is my test code:
<?php
namespace GOC\Bundle\AdminBundle\Tests\Controller;
use FOS\RestBundle\Util\Codes;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use GOC\Bundle\FrameworkBundle\Model\ContextInterface;
use GOC\Bundle\FrameworkBundle\Tests\WebTestCase;
class DashboardControllerTest extends WebTestCase
{
const BASE_URL = '';
/**
* #var ContextInterface|null
*/
protected $context;
public static function setUpBeforeClass()
{
$client = static::createClient([
'environment' => 'test',
'debug' => false,
], [
'HTTP_HOST' => 'demo-cms.dev',
]);
$container = $client->getContainer();
$kernel = $container->get('kernel');
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput(array(
'command' => 'doctrine:mongodb:fixtures:load',
));
$output = new NullOutput();
$application->run($input, $output);
}
/**
* Testing whether the backend is not publicly accessible
*/
public function testFirewallRedirect()
{
$client = static::createClient();
$client->request('GET', $this->buildUrl('/admin/dashboard'));
$response = $client->getResponse();
$this->assertTrue($client->getResponse()->isRedirect($this->buildUrl('http://localhost/admin/login')));
$crawler = $client->request('GET', $response->headers->get('location'));
$this->assertEquals(
1,
$crawler->filter('html:contains("Willkommen")')->count()
);
}
/**
* Testing whether the backend is not publicly accessible
*/
public function testFirewallAccess()
{
$client = static::createClient([
'environment' => 'test',
'debug' => false,
], [
'HTTP_HOST' => 'demo-cms.dev',
]);
$this->logIn($client);
$client->request('GET', $this->buildUrl('/admin/dashboard'));
$response = $client->getResponse();
// This fails...
//$this->assertEquals(Codes::HTTP_OK, $response->getStatusCode());
// Debug statements
$client->request('GET', $this->buildUrl('/forgot-password-sent'));
$response = $client->getResponse();
dump($response);
}
/**
* #param Client $client
*/
protected function logIn(Client $client)
{
$container = $client->getContainer();
$repository = $container->get('goc_account.user_manager')->getRepository();
$user = $repository->getUserByUsername('admin#gardenofconcepts.com', $this->getContext($client));
$firewall = 'main';
$token = new UsernamePasswordToken($user, null, $firewall, $user->getRoles());
$container->get('security.token_storage')->setToken($token);
$session = $container->get('session');
// Saw this somewhere else, makes no difference though
//$session = new Session(new MockArraySessionStorage());
//$session->start();
//$container->set('session', $session);
$session->set('_security_'.$firewall, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$client->getCookieJar()->set($cookie);
}
/**
* #param $url
*
* #return string
*/
protected function buildUrl($url)
{
return $this::BASE_URL . $url;
}
/**
* #param Client $client
*
* #return ContextInterface
*/
protected function getContext(Client $client)
{
if ($this->context) {
return $this->context;
}
$this->context = $client->getContainer()->get('goc_framework.context_manager')->getContextByName('demo');
return $this->context;
}
}
Thanks in advance for any help - it's highly appreciated !
We are not trying to mock the token but actually create one with the following function (which might be adaptable to your situation):
protected function createAuthenticatedClient($username, $password)
{
$client = static::createClient();
$client->request(
'POST',
'/api/v1/login_check',
array(
'username' => $username,
'password' => $password,
)
);
$data = json_decode($client->getResponse()->getContent(), true);
$client = static::createClient();
$client->setServerParameter('HTTP_Authorization', sprintf('Bearer %s', $data['token']));
return $client;
}
After using this like
$client = $this->createAuthenticatedClient('user', 'password');
every request sent will be attached with our actual Bearer.
I am attempting to log a user in programmatically in my functional test on SF 2.7 and FOSUserBundle dev-master. I have already found a good reference to log a user in via SO in this answer - Symfony2 - Tests with FOSUserBundle
The problem is that the second answer, logging the user in programmatically, doesn't work. Here is my code:
<?php
namespace Test\BackEnd\UserBundle\Controller;
use Test\Shared\CoreBundle\Tests\AbstractControllerTest;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\Tools\SchemaTool;
use FA\BackEnd\UserBundle\DataFixtures\ORM\LoadUserData;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
class DefaultController extends AbstractControllerTest
{
public function setUp()
{
$this->client = static::createClient();
$container = $this->client->getContainer();
$doctrine = $container->get('doctrine');
$em = $doctrine->getManager();
$schemaTool = new SchemaTool($em);
$metadata = $em->getMetaDataFactory()->getAllMetadata();
// Drop and recreate tables for all entities
$schemaTool->dropSchema($metadata);
$schemaTool->createSchema($metadata);
$loader = new Loader();
$user = new LoadUserData();
$user->setContainer($container);
$loader->addFixture($user);
$purger = new ORMPurger();
$executor = new ORMExecutor($em, $purger);
$executor->execute($loader->getFixtures());
$session = $container->get('session');
$userManager = $container->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('username' => 'test'));
$firewall = 'default';
$token = new UsernamePasswordToken($user, $user->getPassword(), $firewall, $user->getRoles());
self::$kernel->getContainer()->get('security.token_storage')->setToken($token);
$session->set('_security_'.$firewall, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$this->client->getCookieJar()->set($cookie);
}
public function testProfile()
{
//$this->createAuthorizedClient();
$token = $this->client->getContainer()->get('security.token_storage')->getToken();
$this->client->request('GET', '/profile/');
$this->assertEquals(
200,
$this->client->getResponse()->getStatusCode(),
"/profile isn't accessible"
);
}
}
Whenever I set a break point before the route gets executed, the token is return correctly:
Whenever I get to the function getUser() used by the Controller (http://api.symfony.com/2.7/Symfony/Bundle/FrameworkBundle/Controller/Controller.html#method_getUser) PHPStorm returns an empty token as viewed here:
So I decided to try the following code to log a user in, and it works.
$crawler = $this->client->request('GET', '/login');
$form = $crawler->selectButton('_submit')->form(array(
'_username' => 'test',
'_password' => 'test123',
));
$this->client->submit($form);
$this->client->followRedirect();
Am I not doing something properly whenever I log the user in programmatically? Is the session not being set properly?
Thanks!
Rat
I use this:
protected function createAuthorizedClient()
{
$client = static::createClient();
$container = $client->getContainer();
$session = $container->get('session');
$userManager = $container->get('fos_user.user_manager');
$loginManager = $container->get('fos_user.security.login_manager');
$firewallName = $container->getParameter('fos_user.firewall_name');
$user = $userManager->findUserBy(array('username' => 'USERNAME'));
$loginManager->loginUser($firewallName, $user);
// save the login token into the session and put it in a cookie
$container->get('session')->set('_security_' . $firewallName,
serialize($container->get('security.context')->getToken()));
$container->get('session')->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
$this->client = $client;
}
and then in your test:
public function testMiInfo()
{
$this->createAuthorizedClient();
//else..
}