Commit 77e0b1da authored by Daniel STAN's avatar Daniel STAN

freeradius/auth.py: préparation à l'auth filaire

parent 5446bb81
#!/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:
decision = "accueil", "Hébergeur blacklisté"
# 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
# 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)'
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):
......
# 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))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment