freeradius/auth.py: préparation à l'auth filaire
This commit is contained in:
parent
5446bb8142
commit
77e0b1daad
4 changed files with 159 additions and 68 deletions
|
@ -1,20 +1,21 @@
|
||||||
#!/bin/bash /usr/scripts/python.sh
|
#!/bin/bash /usr/scripts/python.sh
|
||||||
# ⁻*- coding: utf-8 -*-
|
# ⁻*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Draft de fichier d'authentification
|
|
||||||
#
|
|
||||||
# Ce fichier contient la définition de plusieurs fonctions d'interface à freeradius
|
# Ce fichier contient la définition de plusieurs fonctions d'interface à freeradius
|
||||||
# qui peuvent être appelées (suivant les configurations) à certains moment de
|
# qui peuvent être appelées (suivant les configurations) à certains moment de
|
||||||
# l'éxécution.
|
# l'éxécution.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
import netaddr
|
||||||
|
import radiusd # Module magique freeradius (radiusd.py is dummy)
|
||||||
|
|
||||||
import lc_ldap.shortcuts
|
import lc_ldap.shortcuts
|
||||||
from lc_ldap.crans_utils import escape as escape_ldap
|
from lc_ldap.crans_utils import escape as escape_ldap
|
||||||
import lc_ldap.crans_utils
|
import lc_ldap.crans_utils
|
||||||
from gestion.config.config import vlans
|
|
||||||
import lc_ldap.objets
|
import lc_ldap.objets
|
||||||
import radiusd
|
from gestion.config.config import vlans
|
||||||
import netaddr
|
|
||||||
import traceback
|
|
||||||
from gestion.gen_confs.trigger import trigger_generate_cochon as trigger_generate
|
from gestion.gen_confs.trigger import trigger_generate_cochon as trigger_generate
|
||||||
import annuaires_pg
|
import annuaires_pg
|
||||||
|
|
||||||
|
@ -27,13 +28,34 @@ test_v6 = [
|
||||||
|
|
||||||
USERNAME_SUFFIX = '.wifi.crans.org'
|
USERNAME_SUFFIX = '.wifi.crans.org'
|
||||||
|
|
||||||
|
## -*- Logging -*-
|
||||||
|
# Initialisation d'un logger pour faire des stats etc
|
||||||
|
# pour l'instant, on centralise tout sur thot en mode debug
|
||||||
|
logger = logging.getLogger('auth.py')
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s')
|
||||||
|
handler = logging.handlers.SysLogHandler(address = '/dev/log')
|
||||||
|
try:
|
||||||
|
handler.addFormatter(formatter)
|
||||||
|
except AttributeError:
|
||||||
|
handler.formatter = formatter
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
## -*- Types de blacklists -*-
|
||||||
|
#: reject tout de suite
|
||||||
bl_reject = [u'bloq']
|
bl_reject = [u'bloq']
|
||||||
|
|
||||||
|
#: place sur le vlan isolement
|
||||||
bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
|
bl_isolement = [u'virus', u'autodisc_virus', u'autodisc_p2p', u'ipv6_ra']
|
||||||
|
|
||||||
# TODO carte_etudiant: dépend si sursis ou non (regarder lc_ldap)
|
# TODO carte_etudiant: dépend si sursis ou non (regarder lc_ldap)
|
||||||
# TODO LOGSSSSS
|
# TODO LOGSSSSS
|
||||||
|
|
||||||
|
#: place sur accueil
|
||||||
bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement']
|
bl_accueil = [u'carte_etudiant', u'chambre_invalide', u'paiement']
|
||||||
|
|
||||||
# Decorateur utilisé plus tard (same connection)
|
## -*- Decorateurs -*-
|
||||||
|
# À appliquer sur les fonctions qui ont besoin d'une conn ldap
|
||||||
use_ldap_admin = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
|
use_ldap_admin = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
|
||||||
constructor=lc_ldap.shortcuts.lc_ldap_admin)
|
constructor=lc_ldap.shortcuts.lc_ldap_admin)
|
||||||
use_ldap = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
|
use_ldap = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
|
||||||
|
@ -145,13 +167,6 @@ def get_prise_chbre(data):
|
||||||
chbre = None
|
chbre = None
|
||||||
return prise, chbre
|
return prise, chbre
|
||||||
|
|
||||||
def get_ap(data):
|
|
||||||
"""Extrait la prise (wifi)"""
|
|
||||||
## WiFi: NAS-Identifier => vide
|
|
||||||
## Nas-Port => numéro sur l'interface
|
|
||||||
## Nas-IP-Address => adresse IP de la borne
|
|
||||||
pass
|
|
||||||
|
|
||||||
@use_ldap_admin
|
@use_ldap_admin
|
||||||
def register_mac(data, machine, conn):
|
def register_mac(data, machine, conn):
|
||||||
"""Enregistre la mac actuelle sur une machine donnée."""
|
"""Enregistre la mac actuelle sur une machine donnée."""
|
||||||
|
@ -186,8 +201,7 @@ def instantiate(p, *conns):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@radius_event
|
@radius_event
|
||||||
@use_ldap
|
def authorize_wifi(data):
|
||||||
def wifi_authorize(data, conn):
|
|
||||||
"""Section authorize pour le wifi
|
"""Section authorize pour le wifi
|
||||||
(NB: le filaire est en accept pour tout le monde)
|
(NB: le filaire est en accept pour tout le monde)
|
||||||
Éxécuté avant l'authentification proprement dite. On peut ainsi remplir les
|
Éxécuté avant l'authentification proprement dite. On peut ainsi remplir les
|
||||||
|
@ -233,38 +247,93 @@ def wifi_authorize(data, conn):
|
||||||
)
|
)
|
||||||
|
|
||||||
@radius_event
|
@radius_event
|
||||||
@use_ldap
|
def authorize_fil(data):
|
||||||
def post_auth(data, conn):
|
"""For now, do nothing.
|
||||||
|
TODO: check bl_reject.
|
||||||
|
TODO: check chap auth
|
||||||
|
"""
|
||||||
|
return radiusd.RLM_MODULE_OK
|
||||||
|
|
||||||
|
@radius_event
|
||||||
|
def post_auth_wifi(data):
|
||||||
"""Appelé une fois que l'authentification est ok.
|
"""Appelé une fois que l'authentification est ok.
|
||||||
On peut rajouter quelques éléments dans la réponse radius ici.
|
On peut rajouter quelques éléments dans la réponse radius ici.
|
||||||
Comme par exemple le vlan sur lequel placer le client"""
|
Comme par exemple le vlan sur lequel placer le client"""
|
||||||
|
|
||||||
is_wifi = False
|
port, vlan_name, reason = decide_vlan(data, True)
|
||||||
vlan_name = None
|
mac = data.get('Calling-Station-Id', None)
|
||||||
reason = ''
|
|
||||||
identity = "" #TODO
|
|
||||||
prise = ""
|
|
||||||
chbre = None
|
|
||||||
items = get_machines(data)
|
|
||||||
decision = 'adherent',''
|
|
||||||
|
|
||||||
|
log_message = '(wifi) %s -> %s [%s%s]' % \
|
||||||
|
(port, mac, vlan_name, (reason and u': ' + reason).encode(u'utf-8'))
|
||||||
|
logger.info(log_message)
|
||||||
|
radiusd.radlog(radiusd.L_AUTH, log_message)
|
||||||
|
|
||||||
|
# Si NAS ayant des mapping particuliers, à signaler ici
|
||||||
|
vlan_id = vlans[vlan_name]
|
||||||
|
|
||||||
|
# WiFi : Pour l'instant, on ne met pas d'infos de vlans dans la réponse
|
||||||
|
# les bornes wifi ont du mal avec cela
|
||||||
|
return radiusd.RLM_MODULE_OK
|
||||||
|
|
||||||
|
@radius_event
|
||||||
|
def post_auth_fil(data):
|
||||||
|
"""Idem, mais en filaire.
|
||||||
|
Pas testé."""
|
||||||
|
|
||||||
|
port, vlan_name, reason = decide_vlan(data, True)
|
||||||
|
mac = data.get('Calling-Station-Id', None)
|
||||||
|
|
||||||
|
log_message = '(fil) %s -> %s [%s%s]' % \
|
||||||
|
(port, mac, vlan_name, (reason and u': ' + reason).encode(u'utf-8'))
|
||||||
|
logger.info(log_message)
|
||||||
|
radiusd.radlog(radiusd.L_AUTH, log_message)
|
||||||
|
|
||||||
|
# Si NAS ayant des mapping particuliers, à signaler ici
|
||||||
|
vlan_id = vlans[vlan_name]
|
||||||
|
|
||||||
|
# Filaire
|
||||||
|
return (radiusd.RLM_MODULE_UPDATED,
|
||||||
|
(
|
||||||
|
("Tunnel-Type", "VLAN"),
|
||||||
|
("Tunnel-Medium-Type", "IEEE-802"),
|
||||||
|
("Tunnel-Private-Group-Id", '%d' % vlan),
|
||||||
|
),
|
||||||
|
()
|
||||||
|
)
|
||||||
|
|
||||||
|
@use_ldap
|
||||||
|
def decide_vlan(data, is_wifi, conn):
|
||||||
|
"""Décide du vlan non-taggué à assigner, et donne une raison
|
||||||
|
à ce choix.
|
||||||
|
Retourne un (port, vlan_name, reason)
|
||||||
|
où port = est une prise réseau / chambre (si filaire)
|
||||||
|
"wifi" si wifi
|
||||||
|
"""
|
||||||
|
|
||||||
|
if is_wifi:
|
||||||
|
decision = 'wifi',''
|
||||||
|
port = data.get('Called-Station-Id', '?')
|
||||||
|
else:
|
||||||
|
decision = 'adherent',''
|
||||||
|
prise, chbre = get_prise_chbre(data)
|
||||||
|
port = "%s/%s" % (prise, chbre)
|
||||||
|
|
||||||
|
items = get_machines(data)
|
||||||
if not items:
|
if not items:
|
||||||
decision = 'accueil', 'Machine inconnue'
|
return (port, 'accueil', 'Machine inconnue')
|
||||||
return radiusd.RLM_MODULE_NOTFOUND # TODO faire un truc plus propre
|
|
||||||
|
|
||||||
machine = items[0]
|
machine = items[0]
|
||||||
proprio = machine.proprio()
|
proprio = machine.proprio()
|
||||||
|
|
||||||
if isinstance(machine, lc_ldap.objets.machineWifi):
|
if not machine['ipHostNumber']:
|
||||||
decision = 'wifi', ''
|
|
||||||
is_wifi = True
|
|
||||||
|
|
||||||
if not machine['ipHostNumber'] or unicode(machine['macAddress'][0]) in test_v6:
|
|
||||||
decision = 'v6only', 'No IPv4'
|
decision = 'v6only', 'No IPv4'
|
||||||
|
elif unicode(machine['macAddress'][0]) in test_v6:
|
||||||
|
decision = 'v6only', 'Test machine v6'
|
||||||
elif machine['ipHostNumber'][0].value in netaddr.IPNetwork('10.2.9.0/24'):
|
elif machine['ipHostNumber'][0].value in netaddr.IPNetwork('10.2.9.0/24'):
|
||||||
# Cas des personnels logés dans les appartements de l'ENS
|
# Cas des personnels logés dans les appartements de l'ENS
|
||||||
decision = 'appts', 'Personnel ENS'
|
decision = 'appts', 'Personnel ENS'
|
||||||
|
|
||||||
|
# Application des blacklists
|
||||||
for bl in machine.blacklist_actif():
|
for bl in machine.blacklist_actif():
|
||||||
if bl.value['type'] in bl_isolement:
|
if bl.value['type'] in bl_isolement:
|
||||||
decision = 'isolement', unicode(bl)
|
decision = 'isolement', unicode(bl)
|
||||||
|
@ -275,43 +344,28 @@ def post_auth(data, conn):
|
||||||
if not is_wifi:
|
if not is_wifi:
|
||||||
# Si l'adhérent n'est pas membre actif, il doit se brancher depuis la
|
# Si l'adhérent n'est pas membre actif, il doit se brancher depuis la
|
||||||
# prise d'un autre adhérent à jour de cotisation
|
# prise d'un autre adhérent à jour de cotisation
|
||||||
prise, chbre = get_prise_chbre(data)
|
force_ma = False
|
||||||
if proprio['droits']:
|
if chbre is None and not proprio['droits']:
|
||||||
decision = decision[0], decision[1] + ' (force MA)'
|
|
||||||
elif chbre is None:
|
|
||||||
decision = "accueil", "Chambre inconnue"
|
decision = "accueil", "Chambre inconnue"
|
||||||
else:
|
elif chbre is not None:
|
||||||
chbre = escape_ldap(chbre)
|
chbre = escape_ldap(chbre)
|
||||||
hebergeurs = conn.search(u'(&(chambre=%s)(cid=*)(aid=*))' % chbre)
|
hebergeurs = conn.search(u'(&(chambre=%s)(cid=*)(aid=*))' % chbre)
|
||||||
for hebergeur in hebergeurs:
|
for hebergeur in hebergeurs:
|
||||||
if not hebergeur.blacklist_actif():
|
if not hebergeur.blacklist_actif():
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
# Si tous les hebergeurs sont blacklistés, autorisé
|
||||||
|
# uniquement si MA
|
||||||
|
if not proprio['droits']:
|
||||||
decision = "accueil", "Hébergeur blacklisté"
|
decision = "accueil", "Hébergeur blacklisté"
|
||||||
|
else:
|
||||||
|
force_ma = True
|
||||||
|
else:
|
||||||
|
force_ma = True
|
||||||
|
if force_ma:
|
||||||
|
decision = decision[0], decision[1] + ' (force MA)'
|
||||||
|
|
||||||
# Unpack and log
|
return (port,) + decision
|
||||||
if chbre is not None:
|
|
||||||
prise += '/' + chbre
|
|
||||||
|
|
||||||
vlan_name, reason = decision
|
|
||||||
vlan = vlans[vlan_name]
|
|
||||||
radiusd.radlog(radiusd.L_INFO, 'auth.py: %s -> %s [%s%s]' %
|
|
||||||
(prise, identity, vlan_name, (reason and u': ' + reason).encode(u'utf-8'))
|
|
||||||
)
|
|
||||||
|
|
||||||
# WiFi : Pour l'instant, on ne met pas d'infos de vlans dans la réponse
|
|
||||||
# les bornes wifi ont du mal avec cela
|
|
||||||
if is_wifi:
|
|
||||||
return radiusd.RLM_MODULE_OK
|
|
||||||
|
|
||||||
return (radiusd.RLM_MODULE_UPDATED,
|
|
||||||
(
|
|
||||||
("Tunnel-Type", "VLAN"),
|
|
||||||
("Tunnel-Medium-Type", "IEEE-802"),
|
|
||||||
("Tunnel-Private-Group-Id", '%d' % vlan),
|
|
||||||
),
|
|
||||||
()
|
|
||||||
)
|
|
||||||
|
|
||||||
@radius_event
|
@radius_event
|
||||||
def dummy_fun(p):
|
def dummy_fun(p):
|
||||||
|
|
37
freeradius/rlm_python_fil.conf
Normal file
37
freeradius/rlm_python_fil.conf
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Configuration for the Python module.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
python crans_fil {
|
||||||
|
mod_instantiate = freeradius.auth
|
||||||
|
func_instantiate = instantiate
|
||||||
|
|
||||||
|
# Spécifique au WiFi : rempli le mdp
|
||||||
|
mod_authorize = freeradius.auth
|
||||||
|
func_authorize = authorize_fil
|
||||||
|
|
||||||
|
# Renseigne le vlan
|
||||||
|
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||||
|
mod_post_auth = freeradius.auth
|
||||||
|
func_post_auth = post_auth_fil
|
||||||
|
|
||||||
|
# Que faire avant de quitter
|
||||||
|
mod_detach = freeradius.auth
|
||||||
|
func_detach = detach
|
||||||
|
|
||||||
|
# Le reste est dumb et inutile
|
||||||
|
mod_accounting = freeradius.auth
|
||||||
|
func_accounting = dummy_fun
|
||||||
|
|
||||||
|
mod_pre_proxy = freeradius.auth
|
||||||
|
func_pre_proxy = dummy_fun
|
||||||
|
|
||||||
|
mod_post_proxy = freeradius.auth
|
||||||
|
func_post_proxy = dummy_fun
|
||||||
|
|
||||||
|
mod_recv_coa = freeradius.auth
|
||||||
|
func_recv_coa = dummy_fun
|
||||||
|
|
||||||
|
mod_send_coa = freeradius.auth
|
||||||
|
func_send_coa = dummy_fun
|
||||||
|
}
|
|
@ -8,12 +8,12 @@ python crans_wifi {
|
||||||
|
|
||||||
# Spécifique au WiFi : rempli le mdp
|
# Spécifique au WiFi : rempli le mdp
|
||||||
mod_authorize = freeradius.auth
|
mod_authorize = freeradius.auth
|
||||||
func_authorize = wifi_authorize
|
func_authorize = authorize_wifi
|
||||||
|
|
||||||
# Renseigne le vlan
|
# Renseigne le vlan
|
||||||
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||||
mod_post_auth = freeradius.auth
|
mod_post_auth = freeradius.auth
|
||||||
func_post_auth = post_auth
|
func_post_auth = post_auth_wifi
|
||||||
|
|
||||||
# Que faire avant de quitter
|
# Que faire avant de quitter
|
||||||
mod_detach = freeradius.auth
|
mod_detach = freeradius.auth
|
||||||
|
|
|
@ -17,14 +17,14 @@ delattr(sys, 'argv')
|
||||||
auth.instantiate(())
|
auth.instantiate(())
|
||||||
|
|
||||||
p=(
|
p=(
|
||||||
('Calling-Station-Id', 'ba:27:eb:3c:54:d5'),
|
('Calling-Station-Id', 'b0:79:94:cf:d1:9a'),
|
||||||
('User-Name', 'test18'),
|
('User-Name', 'moo-torola'),
|
||||||
)
|
)
|
||||||
|
|
||||||
print repr(auth.wifi_authorize(p))
|
print repr(auth.authorize_wifi(p))
|
||||||
print "wait for 3s, tu peux aller crasher le serveur pg ou ldap"
|
print "wait for 3s, tu peux aller crasher le serveur pg ou ldap"
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
print repr(auth.post_auth(p))
|
print repr(auth.post_auth_wifi(p))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue