Limpiado de Sesiones en Symfony 1.4

Ayer encontre un “bug” (por llamarlo de una manera) en el manejo de sesiones de Symfony 1.4 usando sfGuard, me dí cuenta que cuando inicias una session con el usuario A, guardas un dato en la session del usuario A, deslogeas al usuario A, logueas a un usuario B, en los datos de la session de B estan los datos guardados para el usuario A. Obviamente se pueden dar cuenta de los problemas que puede llegar a traer esto.

Para probar puse en fragmento de código que setea una variable de session con el timestamp, una vez seteada la variable nunca mas se cambia el valor. Se supone que si me logeo la variable se setea por primera vez, al deslogearme la variable debería eliminarse.

Aqui un par de screenshots the la barra de debug de symfony, la primera es antes de logear al user, aqui pueden ver que la session esta limpia.

la segunda es con el el usuario logeado mostrando el valor de session, la variable fue seteada.

y la última es con el usuario deslogeado nuevamente pero con el valor de session ahi.

Si vuelvo a entrar con ese usuario u otro usuario la variable nunca cambia el valor.

El problema sucede tanto si usas setAttribute del Objeto de usuario o si metes el valor directamente en $_SESSION.

Una solución rápida que encontré fue colgarme del evento de user auth change para ver si el usuario se esta deslogeando, en ese caso llamo a un session destroy para limpiar todos los valores de la session.

Como sería esto, bueno, primero, cree una clase para el método que quiero hookear, llamemosla swSessionReset y pongamosla en lib. La clase sería algo así

class swSessionReset {
 
  static public function resetSession($event) {
    if ($event['authenticated'] === false) {
      session_destroy();
    }
  }
 
}

Después tenemos que hookear el método de esta clase. Para eso vamos al ApplicationConfiguration y añadimos estas lineas al método configure.

class applicationNameConfiguration extends sfApplicationConfiguration {
 
  public function configure() {
      //Some Code ....
      $dispatcher = ProjectConfiguration::getActive()->getEventDispatcher();
      $dispatcher->connect('user.change_authentication', 
          array('swSessionReset', 'resetSession')
      );
  }
 
}

Con esto, cada vez que el usuario se deslogue forzaremos la limpieza de todos los valores de session.

Después de ver esto @gerzenstl me hizo notar que Drupal al deslogear un usuario invoca al session_destroy, aca esta el código para que los desconfiados revisen

http://api.drupal.org/api/drupal/modules!user!user.pages.inc/function/user_logout/6

Conclusión, “ojo al parche torrente!”, tengan cuidado con esta consideración por que puede traerles graves problemas de seguridad. Prueben si a ustedes les pasa lo mismo, puede ser que el sitio en el que estoy trabajando actualmente tenga algo modificado que rompe esta funcionalidad (IMHO no creo), después me cuentan como les fue.

Share

sfGuard con LDAP

Ayer me vi en la necesidad de pasar el control de usuarios de un sistema que utiliza el sfGuardPlugin por una base Ldap (Active Directory). Para eso me puse a investigar un poco como hacerlo y ví que el famoso plugin provee de un mecanismo para enganchar una función personalizada para el chequeo del password, dicha función personalizada es la que debe realizar la autenticación del username/password contra el controlador de Dominio; si esta devuelve verdadero significa que el usuario fue validad correctamente, si devuelve falso quiere decir que no. Una consideración a tener en cuenta es que el usuario debe existir dentro de la tabla sf_guard_user por que primero verifica la existencia del username y la autenticación la realiza contra el Controlador de Dominio.

Para poder empezar necesitamos una cuenta válida para bindearnos al arbol LDAP y poder hacer una busqueda por el username (pidanselo a su “amigo” sysadmin). De mas esta decir que debemos tener un Controlador de Dominio funcionando. Tambien deberán tener las extensiones de ldap para PHP, si estan en un debian/ubuntu instalen el paquete php5-ldap.

Paso siguiente es cargar en la base de datos del sistema local todos los nombres de usuario que podrán usar nuestro sistema y que estan en el arbol LDAP, consideren que si quisieran que cualquier usuario definido en el ldap pueda loguearse puedan sincronizar la información o dar de alta al usuario en la base local automáticamente si este no existe la primera vez que intenta loguearse.

El tercer paso es crear una Clase dentro de lib (para que la tome el autoloader de symfony) que posea un método estático llamado checkPassword el cual deberá recibir como argumentos el username y el passoword.  Esto debería quearles algo asi

NOTA: Corregir en el ejemplo los Distinguished Names por los que correspondan en tu arbol ldap.

El paso final es configurar dentro de la configuración de tu aplicación (donde usar el sfGuardAuth) editar el archivo app.yml y especificar que vas a usar la clase LdapLogin y el método checkPassword.

all:
  sf_guard_plugin:
    check_password_callable: [LdapLogin, checkPassword]

Con esto el control de validación user/pass debería ir al controlador de dominio integrando asi tus aplicaciones.

Mas info en http://www.symfony-project.org/plugins/sfGuardPlugin

Share