viernes, 19 de abril de 2013

FreeRADIUS, un servidor AAA de software libre. Algunas cuestiones avanzadas: Contadores SQL, accesos simulataneos y restricción de caracteres prohibidos en nombres de usuarios.


Andrés Gómez
Abril 2013






En una red que necesite controlar de forma segura el acceso de clientes, es aconsejable la gestión centralizada de la autenticación de los mismos. Para ello existe el protocolo RADIUS (acrónimo en inglés de Remote Authentication Dial-In User Server).
En general radius trabaja en 3 procesos, como protocolo AAA. En seguridad informática, el acrónimo AAA corresponde a un tipo de protocolos que realizan tres funciones: Autenticación, Autorización y Contabilización (Authentication, Authorization and Accounting en inglés). La expresión protocolo AAA no se refiere pues a un protocolo en particular, sino a una familia de protocolos que ofrecen los tres servicios citados. (Fuente: Wikipedia)

Freeradius es uno de los más populares servidores Radius, y es totalmente software libre (licencia GPL v2).

No voy a detallar como instalar freeradius en una plataforma Linux, ya que hay un excelente tutorial de como hacerlo y además dejarlo funcional con una base de datos MySQL (base de los usuarios y de parámetros de configuración de las sesiones) y una interfaz gráfica web para la gestión del mismo:


Con ese buen tutorial quedará funcional el servidor básico, puede ser lo suficiente que necesiten. Me voy a referir a temas de un nivel intermedio que he tenido que personalizar, como son Contadores SQL, accesos simultáneos y restricción de caracteres prohibidos en nombres de usuarios.


CONTADORES SQL

Los contadores SQL son mecanismo que ya trae el Freeradius (por defecto desactivados) que permite correr ciertas consultas SQL luego de la autorización de un usuario y que permite devolver parámetros al NAS (Servidor de acceso a la red, que usualmente es un router) para que alimente ciertos parámetros contenidos en los Diccionarios de parámetros que entiende cada NAS y que aunque muchos son parámetros estándar, otros dependen de marcas de equipos. Por ejemplo el contador lo usé para hacer perfiles de navegación (clientes que podian acceder a la red por 4 horas, 1 dia, 1 semana, etc.) y que en cada autenticación calculara cuanto tiempo le quedaba disponible, y luego inhabilitara el acceso de dicho usuario cuando se había acabado su tiempo.

Si se sigue el tutorial mencionado ya se debió haber habilitado el uso de la base de datos ya en el archivo /etc/freeradius/sites-available/default se debe descomentar la líneas

# See "Autorization Queries" in sql.conf
sql

# See "Accounting Queries" in sql.conf
sql

Y en /etc/freeradius/sites-available/inner-tunnel

# See "Autorization Queries" in sql.conf
sql

Luego, para habilitar los contadores SQL, en el archivo /etc/freeradius/radiusd.conf descomentar la linea

$INCLUDE sql/mysql/counter.conf

Los contadores estan en el archivo

/etc/freeradius/sql/mysql/counter.conf

Allí se pueden editar los contadores (ver ejemplo en wiki http://wiki.freeradius.org/modules/Rlm_sqlcounter )

Para entender el funcionamiento profundo de la base de datos es bueno leer la wiki de freeradius, yo detallaré como usé la base de datos para la autenticación de usuarios agrupados en grupos (perfiles).


La tabla radcheck asocia usuarios y contraseña de usuario, ejemplo

USUARIO1 User-Password := PASSWORD1

La tabla radusergroup asocia el usuario con un grupo

USUARIO1 GRUPO1 0

La tabla radacct la usa Freeradius para registrar toda la actividad de cada usuario.

Así que lo que se hace es crear la cantidad de usuarios deseados en la tabla radcheck y luego asosiar cada usuario a un grupo. Los parámetros de configuración de los perfiles se aplican a los grupos, no a los usuarios, aunque si se puede hacer lo mismo con los usuarios directamente.

La tabla radgroupcheck es la que tendrá los parámetros que van a caracterizar el perfil. En mi caso usé un parámetro estándar para todo NAS (en mi caso routers) “Max-All-Session” que especifica el máximo de SEGUNDOS que podrá estar conectado un usuario. Así, si quiero tener un perfil de 1 mes de acceso, el registro en dicha tabla será:

1MES     Max-All-Session     :=     2592000

Donde 2592000 es la cantidad de segundos que hay en 1 mes estándar (30 días).


Los contadores SQL lo que hacen en mi caso es ejecutar una consulta SQL que finalmente obtendrá una cantidad de segundos que al final se RESTAN de los segundos (en este ejemplo 2592000) que son autorizados para cada usuario del perfil. el resultado de esa resta es el tiempo en segundo autorizado para navegar en esa sesión.

LA estructura de un contador es así:

sqlcounter noresetcounter {
counter-name = Max-All-Session-Time
check-name = Max-All-Session
sqlmod-inst = sql
key = User-Name
reset = never
reject = 1
query = "SELECT IFNULL( GREATEST((UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(acctstarttime)), SUM(acctsessiontime)), 1) FROM radacct WHERE username = '%{%k}' LIMIT 1"
Reply-Message := "Tiempo de navegación alcanzado."
}


Donde se debe especificar que se trabaja con la variable Max-All-Session, la clave de evaluación es el User_Name.
El reset tiene un papel importante. Si se pone reset = daily el contador se reseteará a media noche. Entonces si el USUARIO1 agotó su tiempo de acceso el dia de hoy, a partir de media noche podrá volver a acceder.
Yo uso el “reset = never” para que un usuario que se acabó su tiempo de acceso nunca más pueda volver a acceder.
El query es una expresión en SLQ estándar, donde:

UNIX_TIMESTAMP( NOW() ) : fecha y hora de AHORA en formato UNIX
UNIX_TIMESTAMP(acctstarttime): fecha y Hora del primer login dle usuario, en formato UNIX
UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(acctstarttime): esta resta dará en segundos, cuanto tiempo ha pasado desde el tiempo en que el usuario se logueó por primera vez en el servidor, hasta ahora (now).
SUM(acctsessiontime) suma la cantidad total de los registros del campo acctsessiontime (que registra cuantos segundos duró conectado un usuario en cada sesión) y así obtiene el total de tiempo que el usuario ha accedido a la red.
GREATEST((UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(acctstarttime)), SUM(acctsessiontime). Elige el mayor valor entre la resta de AHORA con la hora del primer login del usuario, o el total de tiempo que el usuario ha accedido.

Así toda la consulta hace que el servidor ante cada autenticación evalúe cuanto tiempo ha pasado entre el primer momento de autenticación y el momento actual, el valor quedará en segundos; el Greatest se introduce para eventos en el que varios usuarios acceden simultáneamente con el mismo usuario; por ejemplo el USUARIO2 tiene asignado 1 semana de navegación (2592000 segundos) y acceden varios usuarios al mismo tiempo con USUARIO2, cada acceso independiente contará y será probable que los 2592000 segundos se agoten antes de una semana.

Luego de definir los contadores, hay que editar el archivo
/etc/freeradius/sites-available/default

En la parte final de la seccion authorize escribir el nombre de los contadores, ejemplo
authorize {
...
noresetcounter
dailycounter
monthlycounter
}

Reiniciar el servicio.

/etc/init.d/freeradius restart


RECOMENDACION:

correr en modo de debugging para poder identificar problemas.
freeradius -X


AUTENTICACION POR MAC

Solamente hay que usar el parametro Calling-station-Id en la tabla radcheck asociada al user, con la MAC en formato 00:11:22:33:44:55

No es autenticación automática, es un filtro.

USUARIO1 Calling-Station-Id == 00:23:8B:7F:47:DD


LIMITAR ACCESO SIMULTANEO

Para habilitar uso simultaneo de una cuenta, X veces, hacer:

En /etc/freeradius/sql/mysql/dialup.conf descomentar la linea del sript que dice simul_count_query

En la base de datos en la tabla radcheck (si es solo para un usuario) configurar el maximo de sesiones:
USER1 simultaneous-Use := 1

En la base de datos, e la tabla radgroupcheck (si es para todo un grupo) configurar el maximo de sesione:

GRUPO1 simultaneous-Use := 1

donde 1, se peude reemplazar por la cantidad de sesiones simultaneas por usuario.

Cómo opera? La línea que se descomenta es una consulta SQL, así:

SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM `radacct` WHERE UserName='5MNSWJ' AND AcctStopTime IS NULL


Lo que hace es contar cuantas líneas en la tabla "raddacct" de la base de datos tiene el campo "AcctStopTime" como "NULL" para cierto USUARIO. Esto indica que hay una sesión activa y que aún no se a cerrado. Así que el resultante de la consulta son la sesiones activas para cada usuario.
Sin embargo este método tiene ciertos problemas, ya que si por alguna razón (como reinicio del NAS o del servidor FreeRadius) no se terminó correctamente la sesión, el registro quedará de la misma forma incompleto, es decir con el campo "AcctStopTime" como "NULL". Al ejecutar la consulta se tendrán aparentes "sesiones activas" que según la configuración "simultaneous-Use" de la tabla radcheck inahilitarán la conexión del cliente.

Para información... los scripts que permiten hacer verificación de usuario navegado, en la tabla raddact son:

SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM `radacct` WHERE UserName='USUARIO1' AND AcctStopTime IS NULL


SELECT COUNT(*) FROM `radacct` WHERE UserName='USUARIO1' AND AcctStopTime IS NULL


CARACTERES PROHIBIDOS

Para inhabilitar caracteres en el username hay 2 opciones:

- En el archivo /etc/freeradius/sql/mysql/dialup.conf se describe la forma en que se captura el username, por defecto está descomentada la línea:

sql_user_name = "%{User-Name}"

unas cuantas líneas antes está comentada una línea que hace referencia a los caracteres permitidos y empieza asignando la variable "safe-characters". Se puede copiar esta línea y pegarla debajo de la definicion del username, para que quede así (es un ejemplo donde solo se habilitan los caracteres en mayuscutas ABCDEF y se prohíben el resto):

sql_user_name = "%{User-Name}"
safe-characters = "ABCDEF"

Así el username solo puede contener esos caracteres.
Si bien funciona, tiene una consecuencia importante. Si se inhabilitan por este medio caracteres como el : . veremos que no solamente la restricción aplica al username sino a todos los datos que envía el cliente. Entonces en la base de datos por ejemplo, la direccion MAC ya no tendrá los : sino otros caracteres, lo mismo para con otros campos como la direccion IP. Finalmente también se afecta los datos con que responde el servidor al NAS y se tienen efectos como que el SessionTimeLeft no es reconocido por el NAS y así lo clientes no pueden saber cuanto tiempo de navegación les queda.

- Otra opción es crear expresiones regulares "regex" en la rutina de Autorización del Freeradius.

La rutina de autorización (Authorize{}) desde la version 2.x del freeradius se encuentra en /etc/freeradius/sites-available/default, allí es posible crear scripts que validen la autorización de usuarios, o la rechacen. Así que allí se puede ingresar un loop if que evalúe una expresión regular.
Un ejemplo que invalida (reject) un usuario que tenga espacios en blanco sería:

authorize { ##esta linea ya existe en el archivo
if ("%{User-Name}" =~ / /) {
reject
}
} ##esta linea ya existe en el archivo


o pueden ser regex más estructuradas, por ejemplo que inhabilite usuarios con espacios en blanco pero solo en el el inicio o fin del username:

if ( ("%{User-Name}" =~ / $/) || ("%{User-Name}" =~ /^ /) ){
reject
}







6 comentarios:

  1. Hola Andres, me parece muy buena tu publicación con respecto al acceso simultaneo en Freeradius, pero te queria preguntar un detalle con respecto a Freeradius, el problema que tengo es que la tabla radacct de la base de datos de Freeradius no tiene registros, he seguido los pasos para habilitar los contadores y que en esta tabla se registre la actividad de los usuarios, pero sigo sin entender por que no se ingresan registros a esta.
    Ojala tengas alguna idea del por que de esto.
    Gracias

    ResponderEliminar
  2. Hola. disculpa, no había visto el comentario.
    Pues mira, la tabla radacct es en la que se registran las actividades del radius. Para que funcione lo unico que debe hacer es tener integrado el freeradius con el MySQL. A esta altura aún no influyen los contadores. Lo que debes hacer es solamente asegurarte de hacer la instalacion de freeradius con MySQL y crear un par de usuarios en la base de datos; luego realizar la autenticación de usuarios y esa actividad debe quedar registrada.... un ejemplo: http://blog.e2h.net/2011/07/01/servidor-radius-con-gestion-web-freeradius-daloradius/

    ResponderEliminar
  3. Hola, tengo el mismo problema de Speed, se generan registros en la tabla radpostauth pero en la tabla radacct NO, he seguido todos los pasos pero no hay caso.
    si tienes alguna idea del porque?
    Gracias.

    ResponderEliminar
  4. Hola Rodrigo. Si, puede ser la configuración de tu equipo NAS (enrutador, controladora inalambrica, servidor, etc) en el que le dices cual es el servidor radius al que debe consultar. En ese caso los equipos permiten habilitar si hacen o no "accounting", o si lo hacen en otro servidor. Básicamente el Accounting es llevar los registros de navegacion en raddacct (por defecto). Así que verifica que esté activa la opción de accounting en tu equipo de red, y que esté apuntando a la misma dirección IP del servidor radius.

    ResponderEliminar
  5. Les invitamos a usar nuestro sistema de gestion para routers mikrotik que pronto se actualizara y tendra nuevas herramientas entre ellas un servidor radius EAP con cortes automaticos por fecha y muchas mas novedades registrate es gratis https://www.networkcat.es

    ResponderEliminar
  6. Hola Andrés

    por mi parte ya esta funcionando el radius con mysql y la tabla de radacct esta registrando la actividad de usuarios pero en mi caso solo uso un usuario generico porque no se como agregar los grupos y asociarlos con los usuarios ¿podrías escribir algún ejemplo al respecto? así como de los perfiles... gracias

    ResponderEliminar