I have a Symfony 4.4 project. Login, authentication, and authorization work fine on web.
To simulate authentication in unit tests, I'm using Symfony's example.
...but that's not working. The user is not authenticated in the unit test. I get an Unauthorized with error message "Full authentication is required to access this resource."
My test:
namespace App\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
class DefaultControllerTest extends WebTestCase
{
private $client = null;
public function setUp()
{
$this->client = static::createClient();
}
public function testJsonUserEndpoint()
{
$this->logIn();
$crawler = $this->client->request('GET', '/json/user');
$this->assertNotContains('invalid_credentials', $this->client->getResponse()->getContent());
}
private function logIn()
{
$user = self::$container->get(EntityManagerInterface::class)->getRepository(User::class)->findOneByMail('[email protected]');
$session = $this->client->getContainer()->get('session');
$firewallName = 'main';
$firewallContext = 'main';
$token = new PostAuthenticationGuardToken($user, $firewallName, ['ROLE_USER']);
$session->set('_security_'.$firewallContext, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$this->client->getCookieJar()->set($cookie);
}
}
My firewall:
main:
anonymous:
secret: '%env(APP_SECRET)%'
remember_me:
always_remember_me: true
secret: '%env(APP_SECRET)%'
provider: session_user_provider
guard:
authenticators:
- App\Security\Authenticator\LoginAuthenticator
- App\Security\Authenticator\MobileBridgeAuthenticator
- App\Security\Authenticator\BearerTokenAuthenticator
- App\Security\Authenticator\HashAuthenticator
- App\Security\Authenticator\ClientAuthenticator
entry_point: App\Security\Authenticator\LoginAuthenticator
logout:
path: execute_logout
target: render_login
Unit test failure:
1) App\Tests\Controller\DefaultControllerTest::testJsonUserEndpoint
Failed asserting that '{"status":"invalid_credentials","errors":["Invalid Credentials"],"debug":"Full authentication is required to access this resource.","error":"Unauthorized"}' does not contain "invalid_credentials".
How can I authenticate a user in my unit tests without using the login form?
The problem was that I don't store roles in the database with the user -- they're added in my authenticators -- and passing the roles to
PostAuthenticationGuardToken
wasn't enough. I also had to add them to the user in the token:Actually, it didn't even matter what's in the Token's roles as long as it's an array: