Sugerencias

Tag: authlogic (1 posts)

En busca de la feature perdida en Authlogic

Publicado el 26 Feb 2010

El otro día me tope con algo, cuanto menos curioso. Acababa de poner una aplicación todavía en desarrollo en staging, es decir, había colgado una versión preliminar bajo usuario y clave. Ésta autenticación, un basic http, la había puesto en el servidor web por comodidad, en mi caso apache.

Mi aplicación a su vez cuenta con un back de administración, dónde uso authlogic para la autenticación, y para evitar problemas a la persona que iba a verificar el correcto funcionamiento de todo el site, decidí crear el usuario admin de mi aplicación en base de datos, con los mismo datos de acceso que los usados por la autenticación http del apache.

Cual fué mi sorpresa, cuando una vez deployada mi aplicación, accedí a mi url provisional, puse el usuario y contraseña en la autenticacion que me pedia mi navegador, la del apache, y vi que estaba logado en la aplicación como administrador. Pensé, upss, que extraño, e intenté cerrar sesión. Y digo intente, porque aunque daba a cerrar sesión, yo seguia siempre logado como administrador, y aparentemente la aplicación me estaba borrando mi sesión bien: en los logs la peticion al destroy de mi user_session se procesaba sin problemas, y me sacaba el típico mensaje de flash como que habia sido deslogueado de la aplicación, pero no era asi, yo seguia logado.

Y efectivamente, éste es el momento en el que todos decimos: ¡Cachis!, mi primer bug, no se donde está, pero seguro que es un bug.

Pero no era así, no había ningún bug ni en mi aplicación, ni en authlogic ni mucho menos. Era tan simple como que authlogic, por defecto, da soporte para autenticación http. Por lo tanto, estaba ocurriendo lo siguiente: yo, al meter las credenciales en mi navegador para la autenticación http, estaba mandando en cada petición que se hacía las credenciales, que por casualidad eran las mismas que las de el usuario administardor de base de datos. Authlogic, el muy listo de él, en Authlogic::Session::Base carga los siguientes modulos en éste orden:

      include Params
      include Cookies
      include Session
      include HttpAuth

Entonces, por orden, authlogic lo primero que hace es intertar autenticar al usuario por Params, es decir, intenta autenticar al usuario através de una url única generada para ese fin. Si ese no es el caso, entonces intenta autenticarlo por cookies, sino lo intenta por sesión, y por ultimo lo intenta por autenticación http.

En mi caso, yo estaba simplemente accediendo a la home, por lo que no estaba accediendo con una url única de inicio de sesión, ni tenia cookies para autenticar la usuario, ni estaba intentado crear una sesión para el. Simplemente, mi señor navegador, en cada request estaba mandando las credenciales de la autenticacion al apache, que se propagan evidentemente hasta mi app, y el authlogic las ve, e intenta buscar el usuario recibido y autenticarlo con la clave recibida. Como he dicho, yo tenia mi usuario en base de datos, que era administrador, con las mismas credenciales, y acababa siempre logado como tal :). Una buena feature de authlogic.

Se me ocurren varias utilidades de ésta feature, pero la mas evidente y rapida, es la posibilidad de autenticar a los usuarios de nuestra aplicacion sin necesidad de tener un controlador asociado a ello. Solo con tener nuestro modelo 'User' y 'UserSession':

class User < ActiveRecord::Base
    acts_as_authentic
end

class UserSession < Authlogic::Session::Base
end

y en nuestro application_controller :

  def current_user_session
    return @current_user_session if defined?(@current_user_session)
    @current_user_session = UserSession.find
  end

  def current_user
    return @current_user if defined?(@current_user)
    @current_user = current_user_session && current_user_session.user
  end

podemos automaticamente poner una autenticacion http en nuestro servidor web, y authlogic se encargara de recibir esas credenciales, que van en cada request, y establecer un current_user si procede (si encuentra un usuario en nuestra BD y lo puede autenticar), con lo que conseguimos un sistema de autenticación rapido y ligero. Incluso si no queremos tener la autenticacion en el servidor web, con mandar las credenciales en cada peticion también nos valdria:

http://username:password@example.com

Asi a bote pronto, se me ocurre que es un método rápido para usar autenticación en cualquier tipo de API ligera.

Ultimamente me ha pasado también que a veces, tienes un site en staging o preprodución, con una autenticacion en tu apache, pero necesitas que ciertas acciones no lleven esa autenticación para poder hacer ciertas pruebas de una nueva feature, como por ejemplo, una nueva mega aplicación de facebook que has integrado dentro de tu aplicación rails, y quieres probar contra tu servidor de staging, para lo que necesitas dar acceso a ciertas acciones a las peticiones de facebook. Pues simplemente quitando la autenticacion del apache y con un before_filter se me ocurre que esto se podria conseguir facilmente:

before_filter :authorize_request

private

def authorize_request
    return false unless current_user || params[:controller] == 'facebook_controller'
end

Si depués de todo ésto, decidís que viviríais mas tranquilos sin esta featura simplemente podéis desactivarla:

class UserSession < Authlogic::Session::Base
  allow_http_basic_auth = false
end