php - Autenticación en pruebas funcionales en Symfony 2.1
symfony-2.1 (5)
En mi testinguite (trabajando en 2.0 y ahora 2.1) uso una clase Base WebTestCase que extiende la clase Symfony2 WebTestCase.
Tengo estas dos funciones que crean un cliente anónimo o uno registrado en mis pruebas:
static protected function createClient(array $options = array(), array $server = array())
{
$client = parent::createClient($options, $server);
self::$container = self::$kernel->getContainer();
return $client;
}
protected function createAuthClient($user, $pass)
{
return self::createClient(array(), array(
''PHP_AUTH_USER'' => $user,
''PHP_AUTH_PW'' => $pass,
));
}
Luego, en mis clases de prueba, uso:
$client = static::createClient();
para crear un cliente anon y
$client = static::createAuthClient(''user'',''pass'');
Para crear uno autenticado.
Esto funciona como un encanto en 2.1
Actualmente estoy en el proceso de migrar un proyecto 2.0. * A la actual versión beta 2.1 de Symfony.
En mis pruebas funcionales actualmente tengo este código para crear un cliente con autenticación:
$client = // create a normal test client
$role = ''ROLE_USER'';
$firewallName = ''main'';
$user = // pull a user from db
$client->getCookieJar()->set(new /Symfony/Component/BrowserKit/Cookie(session_name(), true));
$token = new UsernamePasswordToken($user, null, $firewallName, array($role));
self::$kernel->getContainer()->get(''session'')->set(''_security_'' . $firewallName,
serialize($token));
esto funciona como se esperaba en 2.0. * pero no en 2.1, los datos no se configuran en la sesión.
¿Algunas ideas?
Editar (añadiendo más información):
Parece que el problema está en el archivo " Symfony / Component / Security / Http / Firewall / ContextListener " en el método " onKernelResponse ". Hay este código:
if ((null === $token = $this->context->getToken()) || ($token instanceof AnonymousToken)) {
$session->remove(''_security_''.$this->contextKey);
} else {
$session->set(''_security_''.$this->contextKey, serialize($token));
}
en mi caso el if "$ token instanceof AnonymousToken" es verdadero, y debido a eso se elimina la clave de sesión. Si comento ese código todo funciona como se espera.
Así que supongo que mi nueva pregunta es: ¿Qué puedo hacer para que el token no sea anónimo?
He registrado un ticket en: https://github.com/symfony/symfony/issues/3287
Parece que hay un problema existente con Symfony 2.1 RC.
La forma correcta de autenticar al usuario es:
$firewallName = ''your-firewall-name'';
$container = self::$kernel->getContainer()
$token = new UsernamePasswordToken($user, null, $firewallName, $user->getRoles());
$container->get(''security.context'')->setToken($token);
y autenticación de firewall:
$session = $container->get(''session'');
$session->set(''_security_''.$firewallName, serialize($token));
$session->save();
Puedo sugerir otra solución (por lo que funciona para mí). Tengo un proveedor de autenticación personalizado, con lógica complicada y no puedo usar la mecánica http_basic en absoluto.
Necesitas crear una acción especial como esta.
//TestAuthController.php
public function authTestAction(Request $request)
{
// you can add different security checks as you wish
$user_id = $request->query->get("id");
// find user by $user_id using service or user provider service from firewall config
$token = new UsernamePasswordToken($user, null, $firewallName, array($role));
// or another authenticated token
$this->container->get(''security.context'')->setToken($token);
}
agregue routing_test.yml y conéctelo como routing_dev.yml
Lo importante es que esta ruta de autenticación debe existir solo en el entorno de prueba, por razones de seguridad.
//app/config/routing_test.yml
// ... the same routes as in routing_dev.yml
_testauth:
pattern: /__test
defaults: { _controller: MyBundle:TestAuth:authTest }
Luego, en la prueba, simplemente envíe al cliente a esta URL.
public function testSomething()
{
$client = static::createClient();
$client->request(''GET'',''/__test'',array(''id''=>146));
$this->assertTrue($client->getContainer()->get(''security.context'')->isGranted(''ROLE_USER'')) //it will pass;
}
Tuve el mismo problema y encontré una solución al depurar. Dependiendo de su almacenamiento de sesión, es posible que tenga que cambiar su cookie de session_name () a ''MOCKSESSID'' (que se usa si usa la sesión simulada. Creo que si tiene lo siguiente en su config_test.yml, se cambia automáticamente a Mock Almacenamiento de sesión:
framework:
test: ~
Para completar, aquí mi código completo (estoy usando FOS / UserBundle)
protected function createAuthorizedClient($username = ''user'') {
$client = $this->createClient(); //Normal WebTestCase client
$userProvider = $this->get(''fos_user.user_manager'');
$user = $userProvider->loadUserByUsername($username);
//$client->getCookieJar()->set(new Cookie(session_name(), true));
$client->getCookieJar()->set(new Cookie(''MOCKSESSID'', true));
$session = self::$kernel->getContainer()->get(''session'');
$token = new UsernamePasswordToken($user, null, ''main'', $user->getRoles());
$client->getContainer()->get(''security.context'')->setToken($token);
$session->set(''_security_main'', serialize($token));
return $client;
}