auth.py 19.9 KB
Newer Older
Maël Kervella's avatar
Maël Kervella committed
1
# -*- mode: python; coding: utf-8 -*-
lhark's avatar
lhark committed
2 3 4 5
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
6
# Copyirght © 2017  Daniel Stan
lhark's avatar
lhark committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Copyright © 2017  Gabriel Détraz
# Copyright © 2017  Goulven Kermarec
# Copyright © 2017  Augustin Lemesle
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Gabriel Detraz's avatar
Gabriel Detraz committed
25 26 27 28 29 30 31 32 33
"""
Backend python pour freeradius.

Ce fichier contient la définition de plusieurs fonctions d'interface à
freeradius qui peuvent être appelées (suivant les configurations) à certains
moment de l'authentification, en WiFi, filaire, ou par les NAS eux-mêmes.

Inspirés d'autres exemples trouvés ici :
https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_python/
34 35

Inspiré du travail de Daniel Stan au Crans
Gabriel Detraz's avatar
Gabriel Detraz committed
36 37
"""

Maël Kervella's avatar
Maël Kervella committed
38 39
import os
import sys
Maël Kervella's avatar
Maël Kervella committed
40 41
import logging
import radiusd  # Module magique freeradius (radiusd.py is dummy)
Maël Kervella's avatar
Maël Kervella committed
42

Maël Kervella's avatar
Maël Kervella committed
43
from django.core.wsgi import get_wsgi_application
Maël Kervella's avatar
Maël Kervella committed
44
from django.db.models import Q
Maël Kervella's avatar
Maël Kervella committed
45

46 47 48 49 50 51 52 53 54 55 56
proj_path = "/var/www/re2o/"
# This is so Django knows where to find stuff.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
sys.path.append(proj_path)

# This is so my local_settings.py gets loaded.
os.chdir(proj_path)

# This is so models get loaded.
application = get_wsgi_application()

Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
57 58 59
from machines.models import Interface, IpList, Nas, Domain
from topologie.models import Port, Switch
from users.models import User
60
from preferences.models import RadiusOption
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
61 62


Gabriel Detraz's avatar
Gabriel Detraz committed
63 64 65 66
#: Serveur radius de test (pas la prod)
TEST_SERVER = bool(os.getenv('DBG_FREERADIUS', False))


Maël Kervella's avatar
Maël Kervella committed
67
# Logging
Gabriel Detraz's avatar
Gabriel Detraz committed
68 69 70 71 72 73 74 75 76 77 78
class RadiusdHandler(logging.Handler):
    """Handler de logs pour freeradius"""

    def emit(self, record):
        """Process un message de log, en convertissant les niveaux"""
        if record.levelno >= logging.WARN:
            rad_sig = radiusd.L_ERR
        elif record.levelno >= logging.INFO:
            rad_sig = radiusd.L_INFO
        else:
            rad_sig = radiusd.L_DBG
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
79
        radiusd.radlog(rad_sig, record.msg.encode('utf-8'))
Gabriel Detraz's avatar
Gabriel Detraz committed
80

Maël Kervella's avatar
Maël Kervella committed
81

Gabriel Detraz's avatar
Gabriel Detraz committed
82 83 84 85 86 87 88 89
# Initialisation d'un logger (pour logguer unifié)
logger = logging.getLogger('auth.py')
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s')
handler = RadiusdHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)

Maël Kervella's avatar
Maël Kervella committed
90

Gabriel Detraz's avatar
Gabriel Detraz committed
91 92
def radius_event(fun):
    """Décorateur pour les fonctions d'interfaces avec radius.
Maël Kervella's avatar
Maël Kervella committed
93 94
    Une telle fonction prend un uniquement argument, qui est une liste de
    tuples (clé, valeur) et renvoie un triplet dont les composantes sont :
Gabriel Detraz's avatar
Gabriel Detraz committed
95 96 97 98 99 100 101 102 103 104
     * le code de retour (voir radiusd.RLM_MODULE_* )
     * un tuple de couples (clé, valeur) pour les valeurs de réponse (accès ok
       et autres trucs du genre)
     * un tuple de couples (clé, valeur) pour les valeurs internes à mettre à
       jour (mot de passe par exemple)

    On se contente avec ce décorateur (pour l'instant) de convertir la liste de
    tuples en entrée en un dictionnaire."""

    def new_f(auth_data):
Maël Kervella's avatar
Maël Kervella committed
105 106
        """ The function transforming the tuples as dict """
        if isinstance(auth_data, dict):
Gabriel Detraz's avatar
Gabriel Detraz committed
107 108 109 110 111 112 113 114
            data = auth_data
        else:
            data = dict()
            for (key, value) in auth_data or []:
                # Beware: les valeurs scalaires sont entre guillemets
                # Ex: Calling-Station-Id: "une_adresse_mac"
                data[key] = value.replace('"', '')
        try:
Maël Kervella's avatar
Maël Kervella committed
115 116
            # TODO s'assurer ici que les tuples renvoyés sont bien des
            # (str,str) : rlm_python ne digère PAS les unicodes
Gabriel Detraz's avatar
Gabriel Detraz committed
117 118 119
            return fun(data)
        except Exception as err:
            logger.error('Failed %r on data %r' % (err, auth_data))
120
            return radiusd.RLM_MODULE_FAIL
Gabriel Detraz's avatar
Gabriel Detraz committed
121 122 123

    return new_f

124

Gabriel Detraz's avatar
Gabriel Detraz committed
125 126 127 128 129 130
@radius_event
def instantiate(*_):
    """Utile pour initialiser les connexions ldap une première fois (otherwise,
    do nothing)"""
    logger.info('Instantiation')
    if TEST_SERVER:
131
        logger.info(u'DBG_FREERADIUS is enabled')
Gabriel Detraz's avatar
Gabriel Detraz committed
132

Maël Kervella's avatar
Maël Kervella committed
133

Gabriel Detraz's avatar
Gabriel Detraz committed
134 135
@radius_event
def authorize(data):
136
    """On test si on connait le calling nas:
Maël Kervella's avatar
Maël Kervella committed
137 138
    - si le nas est inconnue, on suppose que c'est une requète 802.1X, on la
      traite
139
    - si le nas est connu, on applique 802.1X si le mode est activé
Maël Kervella's avatar
Maël Kervella committed
140 141
    - si le nas est connu et si il s'agit d'un nas auth par mac, on repond
      accept en authorize
142
    """
143
    # Pour les requetes proxifiees, on split
144 145 146
    nas = data.get('NAS-IP-Address', data.get('NAS-Identifier', None))
    nas_instance = find_nas_from_request(nas)
    # Toutes les reuquètes non proxifiées
Gabriel Detraz's avatar
Gabriel Detraz committed
147
    nas_type = None
148
    if nas_instance:
149 150
        nas_type = Nas.objects.filter(nas_type=nas_instance.type).first()
    if not nas_type or nas_type.port_access_mode == '802.1X':
151
        user = data.get('User-Name', '').decode('utf-8', errors='replace')
152
        user = user.split('@', 1)[0]
153
        mac = data.get('Calling-Station-Id', '')
Maël Kervella's avatar
Maël Kervella committed
154 155 156 157 158
        result, log, password = check_user_machine_and_register(
            nas_type,
            user,
            mac
        )
159
        logger.info(log.encode('utf-8'))
160 161
        logger.info(user.encode('utf-8'))

162 163 164
        if not result:
            return radiusd.RLM_MODULE_REJECT
        else:
Maël Kervella's avatar
Maël Kervella committed
165 166 167 168 169 170
            return (
                radiusd.RLM_MODULE_UPDATED,
                (),
                (
                    (str("NT-Password"), str(password)),
                ),
171
            )
Gabriel Detraz's avatar
Gabriel Detraz committed
172

173
    else:
Maël Kervella's avatar
Maël Kervella committed
174 175 176 177 178 179
        return (
            radiusd.RLM_MODULE_UPDATED,
            (),
            (
                ("Auth-Type", "Accept"),
            ),
180
        )
Gabriel Detraz's avatar
Gabriel Detraz committed
181

Maël Kervella's avatar
Maël Kervella committed
182

Gabriel Detraz's avatar
Gabriel Detraz committed
183 184
@radius_event
def post_auth(data):
Maël Kervella's avatar
Maël Kervella committed
185 186 187
    """ Function called after the user is authenticated
    """

188
    nas = data.get('NAS-IP-Address', data.get('NAS-Identifier', None))
root's avatar
root committed
189
    nas_instance = find_nas_from_request(nas)
190
    # Toutes les reuquètes non proxifiées
191 192
    if not nas_instance:
        logger.info(u"Requète proxifiée, nas inconnu".encode('utf-8'))
193 194 195
        return radiusd.RLM_MODULE_OK
    nas_type = Nas.objects.filter(nas_type=nas_instance.type).first()
    if not nas_type:
Maël Kervella's avatar
Maël Kervella committed
196 197 198
        logger.info(
            u"Type de nas non enregistré dans la bdd!".encode('utf-8')
        )
199
        return radiusd.RLM_MODULE_OK
200

Gabriel Detraz's avatar
Gabriel Detraz committed
201
    mac = data.get('Calling-Station-Id', None)
202

Maël Kervella's avatar
Maël Kervella committed
203 204
    # Switch et bornes héritent de machine et peuvent avoir plusieurs
    # interfaces filles
205
    nas_machine = nas_instance.machine
206
    # Si il s'agit d'un switch
207
    if hasattr(nas_machine, 'switch'):
208
        port = data.get('NAS-Port-Id', data.get('NAS-Port', None))
Maël Kervella's avatar
Maël Kervella committed
209 210
        # Pour les infrastructures possédant des switchs Juniper :
        # On vérifie si le switch fait partie d'un stack Juniper
211
        instance_stack = nas_machine.switch.stack
212 213 214
        if instance_stack:
            # Si c'est le cas, on resélectionne le bon switch dans la stack
            id_stack_member = port.split("-")[1].split('/')[0]
Maël Kervella's avatar
Maël Kervella committed
215 216 217 218 219
            nas_machine = (Switch.objects
                           .filter(stack=instance_stack)
                           .filter(stack_member_id=id_stack_member)
                           .prefetch_related(
                               'interface_set__domain__extension'
Maël Kervella's avatar
Maël Kervella committed
220
                           )
Maël Kervella's avatar
Maël Kervella committed
221 222 223
                           .first())
        # On récupère le numéro du port sur l'output de freeradius.
        # La ligne suivante fonctionne pour cisco, HP et Juniper
224
        port = port.split(".")[0].split('/')[-1][-2:]
225
        out = decide_vlan_switch(nas_machine, nas_type, port, mac)
226 227 228 229 230 231 232 233 234 235
        sw_name, room, reason, vlan_id, decision = out

        if decision:
            log_message = '(fil) %s -> %s [%s%s]' % (
                sw_name + u":" + port + u"/" + str(room),
                mac,
                vlan_id,
                (reason and u': ' + reason).encode('utf-8')
            )
            logger.info(log_message)
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
            # Filaire
            return (
                radiusd.RLM_MODULE_UPDATED,
                (
                    ("Tunnel-Type", "VLAN"),
                    ("Tunnel-Medium-Type", "IEEE-802"),
                    ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)),
                ),
                ()
            )
        else:
            log_message = '(fil) %s -> %s [Reject:%s]' % (
                sw_name + u":" + port + u"/" + str(room),
                mac,
                (reason and u': ' + reason).encode('utf-8')
            )
            logger.info(log_message)
254

255
            return radiusd.RLM_MODULE_REJECT
Gabriel Detraz's avatar
Gabriel Detraz committed
256

257 258
    else:
        return radiusd.RLM_MODULE_OK
Gabriel Detraz's avatar
Gabriel Detraz committed
259

Maël Kervella's avatar
Maël Kervella committed
260

Maël Kervella's avatar
Maël Kervella committed
261
# TODO : remove this function
Gabriel Detraz's avatar
Gabriel Detraz committed
262 263 264 265 266
@radius_event
def dummy_fun(_):
    """Do nothing, successfully. (C'est pour avoir un truc à mettre)"""
    return radiusd.RLM_MODULE_OK

Maël Kervella's avatar
Maël Kervella committed
267

Gabriel Detraz's avatar
Gabriel Detraz committed
268 269
def detach(_=None):
    """Appelé lors du déchargement du module (enfin, normalement)"""
Maël Kervella's avatar
Maël Kervella committed
270
    print("*** goodbye from auth.py ***")
Gabriel Detraz's avatar
Gabriel Detraz committed
271 272
    return radiusd.RLM_MODULE_OK

Maël Kervella's avatar
Maël Kervella committed
273

274
def find_nas_from_request(nas_id):
Maël Kervella's avatar
Maël Kervella committed
275
    """ Get the nas object from its ID """
Maël Kervella's avatar
Maël Kervella committed
276 277 278 279 280 281 282
    nas = (Interface.objects
           .filter(
               Q(domain=Domain.objects.filter(name=nas_id)) |
               Q(ipv4=IpList.objects.filter(ipv4=nas_id))
           )
           .select_related('type')
           .select_related('machine__switch__stack'))
root's avatar
root committed
283
    return nas.first()
284

285

286
def check_user_machine_and_register(nas_type, username, mac_address):
Maël Kervella's avatar
Maël Kervella committed
287 288
    """Verifie le username et la mac renseignee. L'enregistre si elle est
    inconnue.
289 290 291
    Renvoie le mot de passe ntlm de l'user si tout est ok
    Utilise pour les authentifications en 802.1X"""
    interface = Interface.objects.filter(mac_address=mac_address).first()
Gabriel Detraz's avatar
Gabriel Detraz committed
292
    user = User.objects.filter(pseudo__iexact=username).first()
293
    if not user:
294 295 296
        return (False, u"User inconnu", '')
    if not user.has_access():
        return (False, u"Adhérent non cotisant", '')
297 298
    if interface:
        if interface.machine.user != user:
Maël Kervella's avatar
Maël Kervella committed
299 300 301 302
            return (False,
                    u"Machine enregistrée sur le compte d'un autre "
                    "user...",
                    '')
303 304
        elif not interface.is_active:
            return (False, u"Machine desactivée", '')
305 306 307
        elif not interface.ipv4:
            interface.assign_ipv4()
            return (True, u"Ok, Reassignation de l'ipv4", user.pwd_ntlm)
308
        else:
309
            return (True, u"Access ok", user.pwd_ntlm)
310
    elif nas_type:
311
        if nas_type.autocapture_mac:
312 313
            result, reason = user.autoregister_machine(mac_address, nas_type)
            if result:
Maël Kervella's avatar
Maël Kervella committed
314 315 316
                return (True,
                        u'Access Ok, Capture de la mac...',
                        user.pwd_ntlm)
317
            else:
318
                return (False, u'Erreur dans le register mac %s' % reason, '')
319 320
        else:
            return (False, u'Machine inconnue', '')
321
    else:
322
        return (False, u"Machine inconnue", '')
323 324


325
def decide_vlan_switch(nas_machine, nas_type, port_number,
326
                       mac_address):
Maël Kervella's avatar
Maël Kervella committed
327 328
    """Fonction de placement vlan pour un switch en radius filaire auth par
    mac.
329
    Plusieurs modes :
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
        - tous les modes:
            - nas inconnu: VLAN_OK
            - port inconnu: Politique définie dans RadiusOption
        - pas de radius sur le port: VLAN_OK
        - force: placement sur le vlan indiqué dans la bdd
        - mode strict:
            - pas de chambre associée: Politique définie
              dans RadiusOption
            - pas d'utilisateur dans la chambre : Rejet
              (redirection web si disponible)
            - utilisateur de la chambre banni ou désactivé : Rejet
              (redirection web si disponible)
            - utilisateur de la chambre non cotisant et non whiteslist:
              Politique définie dans RadiusOption

            - sinon passe à common (ci-dessous)
        - mode common :
            - interface connue (macaddress):
                - utilisateur proprio non cotisant / machine désactivée:
                    Politique définie dans RadiusOption
                - utilisateur proprio banni :
                    Politique définie dans RadiusOption
                - user à jour : VLAN_OK (réassignation de l'ipv4 au besoin)
            - interface inconnue :
                - register mac désactivé : Politique définie
                  dans RadiusOption
                - register mac activé: redirection vers webauth
    Returns:
        tuple avec :
            - Nom du switch (str)
            - chambre (str)
            - raison de la décision (str)
            - vlan_id (int)
            - decision (bool)
364
    """
365
    # Get port from switch and port number
366
    extra_log = ""
367
    # Si le NAS est inconnu, on place sur le vlan defaut
368
    if not nas_machine:
369
        return ('?', u'Chambre inconnue', u'Nas inconnu', RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, True)
370

371
    sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine)))
372

Maël Kervella's avatar
Maël Kervella committed
373 374 375 376 377 378
    port = (Port.objects
            .filter(
                switch=Switch.objects.filter(machine_ptr=nas_machine),
                port=port_number
            )
            .first())
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
379

Maël Kervella's avatar
Maël Kervella committed
380
    # Si le port est inconnu, on place sur le vlan defaut
chirac's avatar
chirac committed
381 382
    # Aucune information particulière ne permet de déterminer quelle
    # politique à appliquer sur ce port
383
    if not port:
384 385 386 387
        return (
            sw_name,
            "Chambre inconnue",
            u'Port inconnu',
388 389
            getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None),
            RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT
390
        )
391

392
    # On récupère le profil du port
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
393
    port_profile = port.get_port_profile
394

Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
395
    # Si un vlan a été précisé dans la config du port,
chirac's avatar
chirac committed
396
    # on l'utilise pour VLAN_OK
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
397 398
    if port_profile.vlan_untagged:
        DECISION_VLAN = int(port_profile.vlan_untagged.vlan_id)
399 400
        extra_log = u"Force sur vlan " + str(DECISION_VLAN)
    else:
401
        DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok')
402

403
    # Si le port est désactivé, on rejette la connexion
404
    if not port.state:
405
        return (sw_name, port.room, u'Port desactivé', None, False)
406

chirac's avatar
chirac committed
407
    # Si radius est désactivé, on laisse passer
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
408
    if port_profile.radius_type == 'NO':
Maël Kervella's avatar
Maël Kervella committed
409 410 411
        return (sw_name,
                "",
                u"Pas d'authentification sur ce port" + extra_log,
412 413
                DECISION_VLAN,
                True)
414

415 416
    # Si le 802.1X est activé sur ce port, cela veut dire que la personne a
    # été accept précédemment
chirac's avatar
chirac committed
417
    # Par conséquent, on laisse passer sur le bon vlan
418
    if (nas_type.port_access_mode, port_profile.radius_type) == ('802.1X', '802.1X'):
chirac's avatar
chirac committed
419
        room = port.room or "Chambre/local inconnu"
420 421 422 423 424 425 426
        return (
            sw_name,
            room,
            u'Acceptation authentification 802.1X',
            DECISION_VLAN,
            True
        )
chirac's avatar
chirac committed
427 428 429

    # Sinon, cela veut dire qu'on fait de l'auth radius par mac
    # Si le port est en mode strict, on vérifie que tous les users
430 431 432 433
    # rattachés à ce port sont bien à jour de cotisation. Sinon on rejette
    # (anti squattage)
    # Il n'est pas possible de se connecter sur une prise strict sans adhérent
    # à jour de cotis dedans
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
434
    if port_profile.radius_mode == 'STRICT':
435 436
        room = port.room
        if not room:
437 438 439 440
            return (
                sw_name,
                "Inconnue",
                u'Chambre inconnue',
441 442
                getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None),
                RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT
443
            )
444

Maël Kervella's avatar
Maël Kervella committed
445 446 447
        room_user = User.objects.filter(
            Q(club__room=port.room) | Q(adherent__room=port.room)
        )
448
        if not room_user:
449 450 451 452 453 454 455
            return (
                sw_name,
                room,
                u'Chambre non cotisante -> Web redirect',
                None,
                False
            )
456
        for user in room_user:
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
457
            if user.is_ban() or user.state != User.STATE_ACTIVE:
458 459 460 461 462 463 464
                return (
                    sw_name,
                    room,
                    u'Utilisateur banni ou désactivé -> Web redirect',
                    None,
                    False
                )
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
465
            elif not (user.is_connected() or user.is_whitelisted()):
466 467 468 469
                return (
                    sw_name,
                    room,
                    u'Utilisateur non cotisant',
470 471
                    getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None),
                    RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT
472
                )
473 474
        # else: user OK, on passe à la verif MAC

475 476
    # Si on fait de l'auth par mac, on cherche l'interface
    # via sa mac dans la bdd
Hugo LEVY-FALK's avatar
Hugo LEVY-FALK committed
477
    if port_profile.radius_mode == 'COMMON' or port_profile.radius_mode == 'STRICT':
478
        # Authentification par mac
Maël Kervella's avatar
Maël Kervella committed
479 480 481 482 483
        interface = (Interface.objects
                     .filter(mac_address=mac_address)
                     .select_related('machine__user')
                     .select_related('ipv4')
                     .first())
484
        if not interface:
485
            room = port.room
486 487 488 489 490 491 492 493 494 495 496 497
            # On essaye de register la mac, si l'autocapture a été activée,
            # on rejette pour faire une redirection web si possible.
            if nas_type.autocapture_mac:
                return (
                    sw_name,
                    room,
                    u'Machine Inconnue -> Web redirect',
                    None,
                    False
                )
            # Sinon on bascule sur la politique définie dans les options
            # radius.
498
            else:
499 500 501 502
                return (
                    sw_name,
                    "",
                    u'Machine inconnue',
503 504
                    getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None),
                    RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT
505 506 507 508
                )

        # L'interface a été trouvée, on vérifie qu'elle est active,
        # sinon on reject
chirac's avatar
chirac committed
509 510
        # Si elle n'a pas d'ipv4, on lui en met une
        # Enfin on laisse passer sur le vlan pertinent
511
        else:
512
            room = port.room
513
            if interface.machine.user.is_ban():
514 515 516 517
                return (
                    sw_name,
                    room,
                    u'Adherent banni',
518 519
                    getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None),
                    RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT
520
                )
521
            if not interface.is_active:
522 523 524 525
                return (
                    sw_name,
                    room,
                    u'Machine non active / adherent non cotisant',
526 527
                    getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None),
                    RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT
528 529 530
                )
            # Si on choisi de placer les machines sur le vlan
            # correspondant à leur type :
531
            if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE':
532 533
                DECISION_VLAN = interface.type.ip_type.vlan.vlan_id
            if not interface.ipv4:
534
                interface.assign_ipv4()
535 536 537 538 539 540 541
                return (
                    sw_name,
                    room,
                    u"Ok, Reassignation de l'ipv4" + extra_log,
                    DECISION_VLAN,
                    True
                )
542
            else:
543 544 545 546 547 548 549
                return (
                    sw_name,
                    room,
                    u'Machine OK' + extra_log,
                    DECISION_VLAN,
                    True
                )