Search code examples
phpsymfonyauthenticationphpunitfunctional-testing

How to properly set the username when simulating authentication with a token in a functional test


I need to write a functional test in order to test that each role has the correct access to the pages.

In order to do that, I'm simulating authentication with a token, but I slightly edited the logIn method, just to call it with custom $username, $role and $firewall:

protected function logIn($username, $role, $firewall)
{
    $session = $this->client->getContainer()->get('session');

    $token = new UsernamePasswordToken($username, null, $firewall, $role);
    $session->set('_security_' . $firewall, serialize($token));
    $session->save();

    $cookie = new Cookie($session->getName(), $session->getId());
    $this->client->getCookieJar()->set($cookie);
}

So I am able to call it specifying which roles should have the fake user:

    $this->logIn('[email protected]', ['ROLE_USER'], "my_firewall");

Then I can test if the user is not allowed or not to access certain routes:

// check if the access is correctly denied to the ROLE_USER
$this->client->request('GET', '/route-not-allowed-to-user');
        $this->assertEquals(403, $this->client->getResponse()->getStatusCode());

// check if the access is correctly allowed to the ROLE_USER
$this->client->request('GET', '/route-allowed-to-user');
        $this->assertNotEquals(403, $this->client->getResponse()->getStatusCode());

Those assertions work, the only problem is that in the view of the route-allowed-to-user I'm using twig to output the username:

{{ app.user.username }}

but it fails. I got status code 500 instead of getting 200, and the following error:

Impossible to access an attribute ("username") on a null variable ...

because app.user is not set.

How can I correctly set the user when simulating an authentication with token?


Solution

  • I've resolved by editing the logIn method as follows:

    protected function logIn($username, $password, $firewall)
    {
        $session = $this->client->getContainer()->get('session');
        $authenticationManager = $this->client->getContainer()->get('security.authentication.manager');
    
        $token = $authenticationManager->authenticate(
            new UsernamePasswordToken(
                $username,
                $password,
                $firewall
            )
        );
    
        $session->set('_security_' . $firewall, serialize($token));
        $session->save();
    
        $cookie = new Cookie($session->getName(), $session->getId());
        $this->client->getCookieJar()->set($cookie);
    }
    

    and using doctrine data fixtures in order to set users and roles.