diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index b318ab63..8450777b 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -355,30 +355,47 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, port=port_number ) .first()) + # Si le port est inconnu, on place sur le vlan defaut + # Aucune information particulière ne permet de déterminer quelle + # politique à appliquer sur ce port if not port: return (sw_name, "Chambre inconnue", u'Port inconnu', VLAN_OK) # On récupère le profil du port port_profil = port.get_port_profil - # Si un vlan a été précisé, on l'utilise pour VLAN_OK + # Si un vlan a été précisé dans la config du port, + # on l'utilise pour VLAN_OK if port_profil.vlan_untagged: DECISION_VLAN = int(port_profil.vlan_untagged.vlan_id) extra_log = u"Force sur vlan " + str(DECISION_VLAN) else: DECISION_VLAN = VLAN_OK + # Si le port est désactivé, on rejette sur le vlan de déconnexion if not port.state: - return (sw_name, port.room, u'Port desactive', VLAN_NOK) + return (sw_name, port.room, u'Port desactivé', VLAN_NOK) + # Si radius est désactivé, on laisse passer if port_profil.radius_type == 'NO': return (sw_name, "", u"Pas d'authentification sur ce port" + extra_log, DECISION_VLAN) - if port_profil.radius_type == 'STRICT': + # Si le 802.1X est activé sur ce port, cela veut dire que la personne a été accept précédemment + # Par conséquent, on laisse passer sur le bon vlan + if nas_type.port_access_mode == '802.1X' and port_profil.radius_type == '802.1X': + room = port.room or "Chambre/local inconnu" + return (sw_name, room, u'Acceptation authentification 802.1X', DECISION_VLAN) + + # 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 + # 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 + if port_profil.radius_mode == 'STRICT': room = port.room if not room: return (sw_name, "Inconnue", u'Chambre inconnue', VLAN_NOK) @@ -393,7 +410,8 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, return (sw_name, room, u'Chambre resident desactive', VLAN_NOK) # else: user OK, on passe à la verif MAC - if port_profil.radius_type == 'COMMON' or port_profil.radius_type == 'STRICT': + # Si on fait de l'auth par mac, on cherche l'interface via sa mac dans la bdd + if port_profil.radius_mode == 'COMMON' or port_profil.radius_mode == 'STRICT': # Authentification par mac interface = (Interface.objects .filter(mac_address=mac_address) @@ -402,15 +420,19 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, .first()) if not interface: room = port.room - # On essaye de register la mac + # On essaye de register la mac, si l'autocapture a été activée + # Sinon on rejette sur vlan_nok if not nas_type.autocapture_mac: return (sw_name, "", u'Machine inconnue', VLAN_NOK) + # On ne peut autocapturer que si on connait la chambre et donc l'user correspondant elif not room: return (sw_name, "Inconnue", u'Chambre et machine inconnues', VLAN_NOK) else: + # Si la chambre est vide (local club, prises en libre services) + # Impossible d'autocapturer if not room_user: room_user = User.objects.filter( Q(club__room=port.room) | Q(adherent__room=port.room) @@ -421,6 +443,8 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, u'Machine et propriétaire de la chambre ' 'inconnus', VLAN_NOK) + # Si il y a plus d'un user dans la chambre, impossible de savoir à qui + # Ajouter la machine elif room_user.count() > 1: return (sw_name, room, @@ -428,11 +452,13 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, 'dans la chambre/local -> ajout de mac ' 'automatique impossible', VLAN_NOK) + # Si l'adhérent de la chambre n'est pas à jour de cotis, pas d'autocapture elif not room_user.first().has_access(): return (sw_name, room, u'Machine inconnue et adhérent non cotisant', VLAN_NOK) + # Sinon on capture et on laisse passer sur le bon vlan else: result, reason = (room_user .first() @@ -452,6 +478,9 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, reason + str(mac_address) ), VLAN_NOK) + # L'interface a été trouvée, on vérifie qu'elle est active, sinon on reject + # Si elle n'a pas d'ipv4, on lui en met une + # Enfin on laisse passer sur le vlan pertinent else: room = port.room if not interface.is_active: diff --git a/search/views.py b/search/views.py index 0ae8470b..73333834 100644 --- a/search/views.py +++ b/search/views.py @@ -262,9 +262,9 @@ def search_single_word(word, filters, user, ) | Q( related__switch__interface__domain__name__icontains=word ) | Q( - custom_profil__name__icontains=word + custom_profile__name__icontains=word ) | Q( - custom_profil__profil_default__icontains=word + custom_profile__profil_default__icontains=word ) | Q( details__icontains=word ) diff --git a/topologie/forms.py b/topologie/forms.py index 63ffc652..ba37d395 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -80,8 +80,8 @@ class EditPortForm(FormRevMixin, ModelForm): optimiser le temps de chargement avec select_related (vraiment lent sans)""" class Meta(PortForm.Meta): - fields = ['room', 'related', 'machine_interface', 'custom_profil', - 'state', 'details'] + fields = ['room', 'related', 'machine_interface', 'custom_profile', + 'state', 'details'] def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) @@ -109,7 +109,7 @@ class AddPortForm(FormRevMixin, ModelForm): 'room', 'machine_interface', 'related', - 'custom_profil', + 'custom_profile', 'state', 'details' ] diff --git a/topologie/migrations/0064_createprofil.py b/topologie/migrations/0064_createprofil.py index 189d1812..2f165386 100644 --- a/topologie/migrations/0064_createprofil.py +++ b/topologie/migrations/0064_createprofil.py @@ -5,53 +5,49 @@ from __future__ import unicode_literals from django.db import migrations +def transfer_profil(apps, schema_editor): + db_alias = schema_editor.connection.alias + port = apps.get_model("topologie", "Port") + profil = apps.get_model("topologie", "PortProfile") + vlan = apps.get_model("machines", "Vlan") + port_list = port.objects.using(db_alias).all() + profil_nothing = profil.objects.using(db_alias).create(name='nothing', profil_default='nothing', radius_type='NO') + profil_uplink = profil.objects.using(db_alias).create(name='uplink', profil_default='uplink', radius_type='NO') + profil_machine = profil.objects.using(db_alias).create(name='asso_machine', profil_default='asso_machine', radius_type='NO') + profil_room = profil.objects.using(db_alias).create(name='room', profil_default='room', radius_type='NO') + profil_borne = profil.objects.using(db_alias).create(name='accesspoint', profil_default='accesspoint', radius_type='NO') + for vlan_instance in vlan.objects.using(db_alias).all(): + if port.objects.using(db_alias).filter(vlan_force=vlan_instance): + custom_profil = profil.objects.using(db_alias).create(name='vlan-force-' + str(vlan_instance.vlan_id), radius_type='NO', vlan_untagged=vlan_instance) + port.objects.using(db_alias).filter(vlan_force=vlan_instance).update(custom_profil=custom_profil) + if port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').count() and port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count(): + profil_room.radius_type = 'MAC-radius' + profil_room.radius_mode = 'STRICT' + common_profil = profil.objects.using(db_alias).create(name='mac-radius-common', radius_type='MAC-radius', radius_mode='COMMON') + no_rad_profil = profil.objects.using(db_alias).create(name='no-radius', radius_type='NO') + port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').update(custom_profil=common_profil) + port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profil=no_rad_profil) + elif port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').count() and port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count(): + profil_room.radius_type = 'MAC-radius' + profil_room.radius_mode = 'COMMON' + strict_profil = profil.objects.using(db_alias).create(name='mac-radius-strict', radius_type='MAC-radius', radius_mode='STRICT') + no_rad_profil = profil.objects.using(db_alias).create(name='no-radius', radius_type='NO') + port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').update(custom_profil=strict_profil) + port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profil=no_rad_profil) + else: + strict_profil = profil.objects.using(db_alias).create(name='mac-radius-strict', radius_type='MAC-radius', radius_mode='STRICT') + common_profil = profil.objects.using(db_alias).create(name='mac-radius-common', radius_type='MAC-radius', radius_mode='COMMON') + port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').update(custom_profil=strict_profil) + port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profil=common_profil) + profil_room.save() + + class Migration(migrations.Migration): dependencies = [ ('topologie', '0063_port_custom_profil'), ] - def transfer_profil(apps, schema_editor): - db_alias = schema_editor.connection.alias - port = apps.get_model("topologie", "Port") - profil = apps.get_model("topologie", "PortProfile") - vlan = apps.get_model("machines", "Vlan") - port_list = port.objects.using(db_alias).all() - profil_nothing = profil.objects.using(db_alias).create(name='nothing', profil_default='nothing', radius_type='NO') - profil_uplink = profil.objects.using(db_alias).create(name='uplink', profil_default='uplink', radius_type='NO') - profil_machine = profil.objects.using(db_alias).create(name='asso_machine', profil_default='asso_machine', radius_type='NO') - profil_room = profil.objects.using(db_alias).create(name='room', profil_default='room', radius_type='NO') - profil_borne = profil.objects.using(db_alias).create(name='accesspoint', profil_default='accesspoint', radius_type='NO') - for vlan_instance in vlan.objects.using(db_alias).all(): - if port.objects.using(db_alias).filter(vlan_force=vlan_instance): - custom_profil = profil.objects.using(db_alias).create(name='vlan-force-' + str(vlan_instance.vlan_id), radius_type='NO', vlan_untagged=vlan_instance) - port.objects.using(db_alias).filter(vlan_force=vlan_instance).update(custom_profil=custom_profil) - if port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').count() and port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count(): - profil_room.radius_type = 'MAC-radius' - profil_room.radius_mode = 'STRICT' - common_profil = profil.objects.using(db_alias).create(name='mac-radius-common', radius_type='MAC-radius', radius_mode='COMMON') - no_rad_profil = profil.objects.using(db_alias).create(name='no-radius', radius_type='NO') - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').update(custom_profil=common_profil) - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profil=no_rad_profil) - elif port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').count() and port.objects.using(db_alias).filter(room__isnull=False).filter(radius='COMMON').count() > port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').count(): - profil_room.radius_type = 'MAC-radius' - profil_room.radius_mode = 'COMMON' - strict_profil = profil.objects.using(db_alias).create(name='mac-radius-strict', radius_type='MAC-radius', radius_mode='STRICT') - no_rad_profil = profil.objects.using(db_alias).create(name='no-radius', radius_type='NO') - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').update(custom_profil=strict_profil) - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profil=no_rad_profil) - else: - strict_profil = profil.objects.using(db_alias).create(name='mac-radius-strict', radius_type='MAC-radius', radius_mode='STRICT') - common_profil = profil.objects.using(db_alias).create(name='mac-radius-common', radius_type='MAC-radius', radius_mode='COMMON') - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='STRICT').update(custom_profil=strict_profil) - port.objects.using(db_alias).filter(room__isnull=False).filter(radius='NO').update(custom_profil=common_profil) - profil_room.save() - - - - def untransfer_profil(apps, schema_editor): - return - operations = [ - migrations.RunPython(transfer_profil, untransfer_profil), + migrations.RunPython(transfer_profil), ] diff --git a/topologie/migrations/0067_auto_20180701_0016.py b/topologie/migrations/0067_auto_20180701_0016.py new file mode 100644 index 00000000..578ee7d6 --- /dev/null +++ b/topologie/migrations/0067_auto_20180701_0016.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-06-30 22:16 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0066_auto_20180630_1855'), + ] + + operations = [ + migrations.RenameField( + model_name='port', + old_name='custom_profil', + new_name='custom_profile', + ), + migrations.AlterField( + model_name='port', + name='state', + field=models.BooleanField(default=True, help_text='Port state Active', verbose_name='Port State Active'), + ), + migrations.AlterField( + model_name='portprofile', + name='arp_protect', + field=models.BooleanField(default=False, help_text='Check if ip is dhcp assigned', verbose_name='Arp protect'), + ), + migrations.AlterField( + model_name='portprofile', + name='dhcp_snooping', + field=models.BooleanField(default=False, help_text='Protect against rogue dhcp', verbose_name='Dhcp snooping'), + ), + migrations.AlterField( + model_name='portprofile', + name='dhcpv6_snooping', + field=models.BooleanField(default=False, help_text='Protect against rogue dhcpv6', verbose_name='Dhcpv6 snooping'), + ), + migrations.AlterField( + model_name='portprofile', + name='flow_control', + field=models.BooleanField(default=False, help_text='Flow control', verbose_name='Flow control'), + ), + migrations.AlterField( + model_name='portprofile', + name='loop_protect', + field=models.BooleanField(default=False, help_text='Protect again loop', verbose_name='Loop Protect'), + ), + migrations.AlterField( + model_name='portprofile', + name='mac_limit', + field=models.IntegerField(blank=True, help_text='Limit of mac-address on this port', null=True, verbose_name='Mac limit'), + ), + migrations.AlterField( + model_name='portprofile', + name='ra_guard', + field=models.BooleanField(default=False, help_text='Protect against rogue ra', verbose_name='Ra guard'), + ), + migrations.AlterField( + model_name='portprofile', + name='radius_mode', + field=models.CharField(choices=[('STRICT', 'STRICT'), ('COMMON', 'COMMON')], default='COMMON', help_text='In case of mac-auth : mode common or strict on this port', max_length=32, verbose_name='RADIUS mode'), + ), + migrations.AlterField( + model_name='portprofile', + name='radius_type', + field=models.CharField(choices=[('NO', 'NO'), ('802.1X', '802.1X'), ('MAC-radius', 'MAC-radius')], help_text='Type of radius auth : inactive, mac-address or 802.1X', max_length=32, verbose_name='RADIUS type'), + ), + migrations.AlterField( + model_name='portprofile', + name='speed', + field=models.CharField(choices=[('10-half', '10-half'), ('100-half', '100-half'), ('10-full', '10-full'), ('100-full', '100-full'), ('1000-full', '1000-full'), ('auto', 'auto'), ('auto-10', 'auto-10'), ('auto-100', 'auto-100')], default='auto', help_text='Port speed limit', max_length=32, verbose_name='Speed'), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index d0534dda..715ccf52 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -391,7 +391,7 @@ class Port(AclMixin, RevMixin, models.Model): blank=True, related_name='related_port' ) - custom_profil = models.ForeignKey( + custom_profile = models.ForeignKey( 'PortProfile', on_delete=models.PROTECT, blank=True, @@ -399,8 +399,8 @@ class Port(AclMixin, RevMixin, models.Model): ) state = models.BooleanField( default=True, - help_text='Etat du port Actif', - verbose_name=_("Etat du port Actif") + help_text='Port state Active', + verbose_name=_("Port State Active") ) details = models.CharField(max_length=255, blank=True) @@ -412,7 +412,8 @@ class Port(AclMixin, RevMixin, models.Model): @cached_property def get_port_profil(self): - """Return the config profil for this port""" + """Return the config profil for this port + :returns: the profile of self (port)""" def profil_or_nothing(profil): port_profil = PortProfile.objects.filter(profil_default=profil).first() if port_profil: @@ -423,8 +424,8 @@ class Port(AclMixin, RevMixin, models.Model): nothing = PortProfile.objects.create(profil_default='nothing', name='nothing', radius_type='NO') return nothing - if self.custom_profil: - return self.custom_profil + if self.custom_profile: + return self.custom_profile elif self.related: return profil_or_nothing('uplink') elif self.machine_interface: @@ -568,57 +569,57 @@ class PortProfile(AclMixin, RevMixin, models.Model): radius_type = models.CharField( max_length=32, choices=TYPES, - help_text="Choix du type d'authentification radius : non actif, mac ou 802.1X", + help_text="Type of radius auth : inactive, mac-address or 802.1X", verbose_name=_("RADIUS type") ) radius_mode = models.CharField( max_length=32, choices=MODES, default='COMMON', - help_text="En cas d'auth par mac, auth common ou strcit sur le port", + help_text="In case of mac-auth : mode common or strict on this port", verbose_name=_("RADIUS mode") ) speed = models.CharField( max_length=32, choices=SPEED, default='auto', - help_text='Mode de transmission et vitesse du port', + help_text='Port speed limit', verbose_name=_("Speed") ) mac_limit = models.IntegerField( null=True, blank=True, - help_text='Limit du nombre de mac sur le port', + help_text='Limit of mac-address on this port', verbose_name=_("Mac limit") ) flow_control = models.BooleanField( default=False, - help_text='Gestion des débits', + help_text='Flow control', verbose_name=_("Flow control") ) dhcp_snooping = models.BooleanField( default=False, - help_text='Protection dhcp pirate', + help_text='Protect against rogue dhcp', verbose_name=_("Dhcp snooping") ) dhcpv6_snooping = models.BooleanField( default=False, - help_text='Protection dhcpv6 pirate', + help_text='Protect against rogue dhcpv6', verbose_name=_("Dhcpv6 snooping") ) arp_protect = models.BooleanField( default=False, - help_text='Verification assignation de l\'IP par dhcp', + help_text='Check if ip is dhcp assigned', verbose_name=_("Arp protect") ) ra_guard = models.BooleanField( default=False, - help_text='Protection contre ra pirate', + help_text='Protect against rogue ra', verbose_name=_("Ra guard") ) loop_protect = models.BooleanField( default=False, - help_text='Protection contre les boucles', + help_text='Protect again loop', verbose_name=_("Loop Protect") ) @@ -635,6 +636,10 @@ class PortProfile(AclMixin, RevMixin, models.Model): def security_parameters_enabled(self): return [parameter for parameter in self.security_parameters_fields if getattr(self, parameter)] + @cached_property + def security_parameters_as_str(self): + return ','.join(self.security_parameters_enabled) + def __str__(self): return self.name diff --git a/topologie/templates/topologie/aff_port.html b/topologie/templates/topologie/aff_port.html index 45e81e06..86216f15 100644 --- a/topologie/templates/topologie/aff_port.html +++ b/topologie/templates/topologie/aff_port.html @@ -32,7 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Nom" %} | -{% trans "Default pour" %} | -{% trans "VLANs" %} | -{% trans "Réglages RADIUS" %} | -{% trans "Vitesse" %} | -{% trans "Mac address limit" %} | -{% trans "Sécurité" %} | -- | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
{% trans "Name" %} | +{% trans "Default for" %} | +{% trans "VLANs" %} | +{% trans "RADIUS settings" %} | +{% trans "Speed" %} | +{% trans "Mac address limit" %} | +{% trans "Security" %} | ++ | ||||||
{{port_profile.name}} | {{port_profile.profil_default}} | -
- Untagged : {{port_profile.vlan_untagged}}
- - Tagged : {{port_profile.vlan_tagged.all|join:", "}} - |
-
- Type : {{port_profile.radius_type}}
- {% if port_profile.radius_type == "MAC-radius" %}
- - Mode : {{port_profile.radius_mode}} |
- {% endif %}
- {{port_profile.speed}} | -{{port_profile.mac_limit}} | -{{port_profile.security_parameters_enabled|join:" "}} |
- - {% include 'buttons/history.html' with href='topologie:history' name='portprofile' id=port_profile.pk %} - {% can_edit port_profile %} - {% include 'buttons/edit.html' with href='topologie:edit-port-profile' id=port_profile.pk %} - {% acl_end %} - {% can_delete port_profile %} - {% include 'buttons/suppr.html' with href='topologie:del-port-profile' id=port_profile.pk %} - {% acl_end %} - | +
+ {% if port_profile.vlan_untagged %}
+ Untagged : {{port_profile.vlan_untagged}}
+ + {% endif %} + {% if port_profile.vlan_untagged %} + Tagged : {{port_profile.vlan_tagged.all|join:", "}} + {% endif %} + |
+
+ Type : {{port_profile.radius_type}}
+ {% if port_profile.radius_type == "MAC-radius" %}
+ + Mode : {{port_profile.radius_mode}} |
+ {% endif %}
+ {{port_profile.speed}} | +{{port_profile.mac_limit}} | +{{port_profile.security_parameters_enabled|join:" "}} |
+ + {% include 'buttons/history.html' with href='topologie:history' name='portprofile' id=port_profile.pk %} + {% can_edit port_profile %} + {% include 'buttons/edit.html' with href='topologie:edit-port-profile' id=port_profile.pk %} + {% acl_end %} + {% can_delete port_profile %} + {% include 'buttons/suppr.html' with href='topologie:del-port-profile' id=port_profile.pk %} + {% acl_end %} + |