How to test Symfony2 api with DunglasAngularCsrfBundle - php

I use Symfony2 with DunglasAngularCsrfBundle and when i run my PHpunit test it get error {"code":403,"message":"Bad CSRF token."}
If auth user with http basic
self::$user_client = static::createClient(array(), array(
'PHP_AUTH_USER' => 'user1#mail.com',
'PHP_AUTH_PW' => 'user1',
'HTTP_HOST' => static::getHost()
));
This condition return false in EventListener\AngularCsrfValidationListener
if (!$value || !$this->angularCsrfTokenManager->isTokenValid($value)) {
throw new AccessDeniedHttpException('Bad CSRF token.');
}
generated token in test not equal, i try another auth like this:
protected function logIn($email)
{
$this->client = static::createClient();
$user = $this->client->getContainer()
->get('doctrine')
->getManager()
->getRepository('UserBundle:User')
->findOneByEmail($email);
$providerKey = static::$kernel->getContainer()->getParameter('fos_user.firewall_name');
$token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
$session = $this->client->getContainer()->get('session');
$session->set('_security_'.$providerKey, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$this->client->getCookieJar()->set($cookie);
}
token not created. Return false in Symfony\Component\Security\Csrf\CsrfTokenManager::isTokenValid:
$this->storage->hasToken($token->getId())
Please help to resolve this issue, thanks

Solved
self::$client->request('GET', '/')
set token in cookie

Related

Symfony 5 - Panther : invalid cookie domain

I'm trying to use Panther for PhpUnit Tests in my Symfony 5 application.
When I try to log an user, like this :
$client = static::createPantherClient();
/** #var User $user */
$user = $this->getSuperAdminAccount();
$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);
when I run the test, I get:
Panther Facebook\WebDriver\Exception\InvalidCookieDomainException :
invalid cookie domain
Can someone help me please ?
if anyone has the same problem, I found a solution on Github : https://github.com/symfony/panther/issues/283#issuecomment-674524048
Just request domain before adding a cookie :
$client->request('GET', 'https://www.google.com/');
$client->getCookieJar()->set(new Cookie('my_cookie', 'hello', domain: '.google.com'));
$client->request('GET', 'https://www.google.com/');

Symfony Panther authentication seems not to be taken into account

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');
}

Testing with sessions in symfony

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

Logging a User in Programmatically for a Functional Test with FOSUserBundle

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..
}

webtests symfony 2.5 with Fosuserbundle

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

Categories