2012-07-12 13 views
19

Actualmente estoy en el proceso de migrar un proyecto 2.0. * A la versión 2.1 beta actual de Symfony.Autenticación en pruebas funcionales en Symfony 2.1

En mis pruebas funcionales Actualmente tengo el 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 espera en 2.0 * pero no en 2.1, los datos no se consiga el conjunto de la sesión.

¿Alguna idea?

Editar (añadiendo más información):

parece que el problema radica en el archivo "Symfony \ Component \ Security \ HTTP \ Firewall \ ContextListener" en el método "onKernelResponse". No es 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 caso de "símbolo $ instanceof AnonymousToken" es cierto, y debido a que la clave de sesión se elimina. si hago un comentario sobre ese código todo funciona como se espera.

Supongo que mi nueva pregunta es: ¿Qué puedo hacer para que el token no sea anónimo?

+0

estoy usando un fragmento muy similares a los suyos para iniciar sesión un usuario para las pruebas funcionales particulares También estoy actualizando a 2.1 y sería genial hacerlo funcionar, ya que muchas de mis pruebas funcionales ahora están fallando. –

+0

Veo eso en ContextListener.php, ac todo está hecho a $ this-> context-> setToken (null), y eso se llama porque $ session === null? Mmm ... –

+1

Cuando comento ContextListener.php: línea 77 - $ this-> context-> setToken (null), ¡mis pruebas funcionan perfectamente! ¡Entonces quizás sea una pista! –

Respuesta

11

manera adecuada para autenticar el 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 firewall de autenticación:

$session = $container->get('session'); 
$session->set('_security_'.$firewallName, serialize($token)); 
$session->save(); 
+0

Después de cavar un poco, llegué a la misma conclusión. Pero esto no funciona en mis pruebas. Gracias por su respuesta de todos modos. – smoove

+0

¿Ha eliminado también la sesión nueva mirando esta línea: $ client-> getCookieJar() -> set (new \ Symfony \ Component \ BrowserKit \ Cookie (session_name(), true)); –

+0

He intentado con y sin esa línea y no cambia nada. – smoove

1

En mi suite de pruebas (que trabaja en 2.0 y ahora en la versión 2.1) utilizo una WebTestCase de clase base que amplía la clase Symfony2 WebTestCase.

que tienen estas dos funciones que crean un cliente anónimo o registrado una 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, 
    )); 
} 

Entonces, en mis clases de prueba, yo uso:

$client = static::createClient(); 

para crear un anon cliente y

$client = static::createAuthClient('user','pass'); 

para crear una autenticada.

Esto funciona como un encanto en 2.1

1

puedo sugerir otra solución (por lo tanto, trabaja para mí). Tengo un proveedor de autenticación personalizado, con una lógica complicada y no puedo usar la mecánica http_basic en absoluto.

Es necesario crear acción especial como este

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

complemento routing_test.yml y conectarlo al igual que routing_dev.yml

Lo importante es que esta ruta de autenticación solo debe existir 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 } 

A continuación, en la prueba simplemente enviar cliente para 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; 
} 
+0

Esto funcionó para mí, mientras que otros métodos no lo han hecho (utilizando Sf2.3) – caponica

1

que tenía el mismo problema y encontré una solución durante la depuración. Dependiendo de su almacenamiento de sesión, es posible que tenga que cambiar su cookie de session_name() a 'MOCKSESSID' (que se utiliza 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 las sesiones:

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; 
} 
Cuestiones relacionadas