Ruby y Ejabberd

Posted in Original Content by David Cavalero - last update: Dec 30, 2023

If you arrive on this page - you were probably following a link. This page was created by David Cavalera, who no longer owns this domain. It is still linked/indexed - so I decided to keep it online You can find David on Twitter/X or LinkedIn

Original version of this page can still be found on the internet archive

<Original content below:>

Ejabberd es uno de los servidores jabber más populares que existen y una de sus características más destacable es la posibilidad de autenticar usuarios de forma externa. Con esta opción podremos integrar mensajería jabber en nuestra aplicación sin tener que modificar nuestra base de datos o migrar nuestros usuario ya registrados a la base de datos del servidor.

En la página del proyecto podemos encontrar varios scripts para autenticar usuarios contra distintas bases de datos o servicios de directorio.

En este artículo vamos a ver como configurar el servidor para que autentique a los usuarios a través de un script en Ruby contra una base de datos Mysql.

La configuración del servidor es sencilla, dentro del directorio donde tenemos instalado ejabberd abrimos el archivo “conf/ejabberd.cfg” comentando la línea donde se indica la autenticación interna:

%{auth_method, internal}

y descomentando las líneas donde se indica la autenticación externa y el path al script que vamos a utilizar:

{auth_method, external}.
{extauth_program, "/var/www/apps/trunk/config/ejabberdAuth.rb"}.

A la hora de introducir los parámetros de conexión con nuestra base de datos tenemos varias opciones, pero si estamos desarrollado una aplicación con Ruby on Rails podemos recoger estos datos directamente de nuestra configuración:

environment = 'development'
#PATH ABSOLUTO AL FICHERO DE CONFIGURACION
config_file = '/var/www/apps/trunk/config/database.yml'
cfg = YAML.load_file(config_file)[environment]

Para conectarnos con la base de datos usaremos el módulo DBI para ruby:

host = cfg['host'] || '127.0.0.1'
db_con = "DBI:Mysql:#{cfg['database']}:#{host}"
@db = DBI.connect db_con, cfg['username'] , cfg['password']

Los paquetes que el servidor ejabberd envia y recibe del script tienen un formato determando. Cuando el script recibe un paquete dentro de sus dos primeros bits se encuentra la longitud de la cadena de datos que tenemos que leer. Esta cadena tiene un formato determinado:

operación : usuario : nombre del servidor jabber : contraseña Por ejemplo:

auth:david:thinkincode.net:david

La respuesta al servidor debe ser 1 en caso de que la operación sea correcta o 0 en caso contrario. Esta respuesta también está empaquetada con los dos primeros bits libres para su longitud.

buffer = String.new
while STDIN.sysread(2, buffer) && buffer.length == 2

  length = buffer.unpack('n')[0]
  operation, username, domain, password = 
      STDIN.sysread(length).split(':')	      
	      
  response = case operation 
      when 'auth'
          auth username, password.chomp
      when 'isuser'              
          isuser username
      else
          0
      end
				    
  STDOUT.syswrite([2, response].pack('nn'))
end

Una vez que hemos obtenido los datos introducidos por el usuario sólo tendremos que validarnos contra nuestra base de datos según la operación que hayamos recibido. El método para autenticar el usuario podría quedar así:

def auth(username, password)
  row = @db.select_one("select password from users"
    " where user_name = ? and activated_at IS NOT NULL", 
    username)
    
  return (1 if row and row['password'] == password) || 0
end

Una vez terminado el script tendríamos que arancar el servidor jabber para que nuestros usuarios puedan conectarse con su cliente favorito usando el usuario y contraseña que han introducido en nuestra aplicación.

Un pequeño truco para ver si el servidor ha arrancado correctamente es ver si tenemos un proceso corriendo con el script que hemos configurado.

Dejo el código completo del script para poder ver el ejemplo más detalladamente.

<End or original content>

Other articles