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
|
||||
# ⁻*- coding: utf-8 -*-
|
||||
#
|
||||
# Draft de fichier d'authentification
|
||||
#
|
||||
# Ce fichier contient la définition de plusieurs fonctions d'interface à freeradius
|
||||
# qui peuvent être appelées (suivant les configurations) à certains moment de
|
||||
# l'éxécution.
|
||||
#
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
import netaddr
|
||||
import radiusd # Module magique freeradius (radiusd.py is dummy)
|
||||
|
||||
import lc_ldap.shortcuts
|
||||
from lc_ldap.crans_utils import escape as escape_ldap
|
||||
import lc_ldap.crans_utils
|
||||
from gestion.config.config import vlans
|
||||
import lc_ldap.objets
|
||||
import radiusd
|
||||
import netaddr
|
||||
import traceback
|
||||
from gestion.config.config import vlans
|
||||
from gestion.gen_confs.trigger import trigger_generate_cochon as trigger_generate
|
||||
import annuaires_pg
|
||||
|
||||
|
@ -27,13 +28,34 @@ test_v6 = [
|
|||
|
||||
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']
|
||||
|
||||
#: place sur le vlan isolement
|
||||
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 LOGSSSSS
|
||||
|
||||
#: place sur accueil
|
||||
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,
|
||||
constructor=lc_ldap.shortcuts.lc_ldap_admin)
|
||||
use_ldap = lc_ldap.shortcuts.with_ldap_conn(retries=2, delay=5,
|
||||
|
@ -145,13 +167,6 @@ def get_prise_chbre(data):
|
|||
chbre = None
|
||||
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
|
||||
def register_mac(data, machine, conn):
|
||||
"""Enregistre la mac actuelle sur une machine donnée."""
|
||||
|
@ -186,8 +201,7 @@ def instantiate(p, *conns):
|
|||
pass
|
||||
|
||||
@radius_event
|
||||
@use_ldap
|
||||
def wifi_authorize(data, conn):
|
||||
def authorize_wifi(data):
|
||||
"""Section authorize pour le wifi
|
||||
(NB: le filaire est en accept pour tout le monde)
|
||||
Éxécuté avant l'authentification proprement dite. On peut ainsi remplir les
|
||||
|
@ -233,38 +247,93 @@ def wifi_authorize(data, conn):
|
|||
)
|
||||
|
||||
@radius_event
|
||||
@use_ldap
|
||||
def post_auth(data, conn):
|
||||
def authorize_fil(data):
|
||||
"""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.
|
||||
On peut rajouter quelques éléments dans la réponse radius ici.
|
||||
Comme par exemple le vlan sur lequel placer le client"""
|
||||
|
||||
is_wifi = False
|
||||
vlan_name = None
|
||||
reason = ''
|
||||
identity = "" #TODO
|
||||
prise = ""
|
||||
chbre = None
|
||||
items = get_machines(data)
|
||||
decision = 'adherent',''
|
||||
port, vlan_name, reason = decide_vlan(data, True)
|
||||
mac = data.get('Calling-Station-Id', None)
|
||||
|
||||
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:
|
||||
decision = 'accueil', 'Machine inconnue'
|
||||
return radiusd.RLM_MODULE_NOTFOUND # TODO faire un truc plus propre
|
||||
return (port, 'accueil', 'Machine inconnue')
|
||||
|
||||
machine = items[0]
|
||||
proprio = machine.proprio()
|
||||
|
||||
if isinstance(machine, lc_ldap.objets.machineWifi):
|
||||
decision = 'wifi', ''
|
||||
is_wifi = True
|
||||
|
||||
if not machine['ipHostNumber'] or unicode(machine['macAddress'][0]) in test_v6:
|
||||
if not machine['ipHostNumber']:
|
||||
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'):
|
||||
# Cas des personnels logés dans les appartements de l'ENS
|
||||
decision = 'appts', 'Personnel ENS'
|
||||
|
||||
# Application des blacklists
|
||||
for bl in machine.blacklist_actif():
|
||||
if bl.value['type'] in bl_isolement:
|
||||
decision = 'isolement', unicode(bl)
|
||||
|
@ -275,43 +344,28 @@ def post_auth(data, conn):
|
|||
if not is_wifi:
|
||||
# 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, chbre = get_prise_chbre(data)
|
||||
if proprio['droits']:
|
||||
decision = decision[0], decision[1] + ' (force MA)'
|
||||
elif chbre is None:
|
||||
force_ma = False
|
||||
if chbre is None and not proprio['droits']:
|
||||
decision = "accueil", "Chambre inconnue"
|
||||
else:
|
||||
elif chbre is not None:
|
||||
chbre = escape_ldap(chbre)
|
||||
hebergeurs = conn.search(u'(&(chambre=%s)(cid=*)(aid=*))' % chbre)
|
||||
for hebergeur in hebergeurs:
|
||||
if not hebergeur.blacklist_actif():
|
||||
break
|
||||
else:
|
||||
# Si tous les hebergeurs sont blacklistés, autorisé
|
||||
# uniquement si MA
|
||||
if not proprio['droits']:
|
||||
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
|
||||
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),
|
||||
),
|
||||
()
|
||||
)
|
||||
return (port,) + decision
|
||||
|
||||
@radius_event
|
||||
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
|
||||
mod_authorize = freeradius.auth
|
||||
func_authorize = wifi_authorize
|
||||
func_authorize = authorize_wifi
|
||||
|
||||
# Renseigne le vlan
|
||||
# remplacer par dummy_fun pour ignorer le tagging de vlan
|
||||
mod_post_auth = freeradius.auth
|
||||
func_post_auth = post_auth
|
||||
func_post_auth = post_auth_wifi
|
||||
|
||||
# Que faire avant de quitter
|
||||
mod_detach = freeradius.auth
|
||||
|
|
|
@ -17,14 +17,14 @@ delattr(sys, 'argv')
|
|||
auth.instantiate(())
|
||||
|
||||
p=(
|
||||
('Calling-Station-Id', 'ba:27:eb:3c:54:d5'),
|
||||
('User-Name', 'test18'),
|
||||
('Calling-Station-Id', 'b0:79:94:cf:d1:9a'),
|
||||
('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"
|
||||
sys.stdout.flush()
|
||||
|
||||
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