diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index ab10d457..3fa7e23f 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -57,14 +57,9 @@ application = get_wsgi_application() from machines.models import Interface, IpList, Nas, Domain from topologie.models import Port, Switch from users.models import User -from preferences.models import OptionalTopologie +from preferences.models import RadiusOption -options, created = OptionalTopologie.objects.get_or_create() -VLAN_NOK = options.vlan_decision_nok.vlan_id -VLAN_OK = options.vlan_decision_ok.vlan_id -RADIUS_POLICY = options.radius_general_policy - #: Serveur radius de test (pas la prod) TEST_SERVER = bool(os.getenv('DBG_FREERADIUS', False)) @@ -287,6 +282,7 @@ def find_nas_from_request(nas_id): .select_related('machine__switch__stack')) return nas.first() + def check_user_machine_and_register(nas_type, username, mac_address): """Verifie le username et la mac renseignee. L'enregistre si elle est inconnue. @@ -327,32 +323,50 @@ def check_user_machine_and_register(nas_type, username, mac_address): def decide_vlan_switch(nas_machine, nas_type, port_number, - mac_address): + mac_address): """Fonction de placement vlan pour un switch en radius filaire auth par mac. Plusieurs modes : - - nas inconnu, port inconnu : on place sur le vlan par defaut VLAN_OK - - pas de radius sur le port : VLAN_OK - - bloq : VLAN_NOK - - force : placement sur le vlan indiqué dans la bdd - - mode strict : - - pas de chambre associée : VLAN_NOK - - pas d'utilisateur dans la chambre : VLAN_NOK - - cotisation non à jour : VLAN_NOK - - sinon passe à common (ci-dessous) - - mode common : - - interface connue (macaddress): - - utilisateur proprio non cotisant ou banni : VLAN_NOK - - user à jour : VLAN_OK - - interface inconnue : - - register mac désactivé : VLAN_NOK - - register mac activé -> redirection vers webauth + - 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) """ # Get port from switch and port number extra_log = "" # Si le NAS est inconnu, on place sur le vlan defaut if not nas_machine: - return ('?', u'Chambre inconnue', u'Nas inconnu', VLAN_OK, True) + return ('?', u'Chambre inconnue', u'Nas inconnu', RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, True) sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) @@ -367,7 +381,13 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, # 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, True) + return ( + sw_name, + "Chambre inconnue", + u'Port inconnu', + RadiusOption('unknown_port_vlan').vlan_id, + RadiusOption('unknown_port')!= RadiusOption.REJECT + ) # On récupère le profil du port port_profile = port.get_port_profile @@ -378,11 +398,11 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, DECISION_VLAN = int(port_profile.vlan_untagged.vlan_id) extra_log = u"Force sur vlan " + str(DECISION_VLAN) else: - DECISION_VLAN = VLAN_OK + DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok') - # Si le port est désactivé, on rejette sur le vlan de déconnexion + # Si le port est désactivé, on rejette la connexion if not port.state: - return (sw_name, port.room, u'Port desactivé', VLAN_NOK, True) + return (sw_name, port.room, u'Port desactivé', None, False) # Si radius est désactivé, on laisse passer if port_profile.radius_type == 'NO': @@ -392,33 +412,68 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, DECISION_VLAN, True) - # Si le 802.1X est activé sur ce port, cela veut dire que la personne a été accept précédemment + # 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_profile.radius_type == '802.1X': + if (nas_type.port_access_mode, port_profile.radius_type) == ('802.1X', '802.1X'): room = port.room or "Chambre/local inconnu" - return (sw_name, room, u'Acceptation authentification 802.1X', DECISION_VLAN, True) + return ( + sw_name, + room, + u'Acceptation authentification 802.1X', + DECISION_VLAN, + True + ) # 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 + # 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_profile.radius_mode == 'STRICT': room = port.room if not room: - return (sw_name, "Inconnue", u'Chambre inconnue', VLAN_NOK, True) + return ( + sw_name, + "Inconnue", + u'Chambre inconnue', + RadiusOption('unknown_room_vlan').vlan_id, + RadiusOption('unknown_room')!= RadiusOption.REJECT + ) room_user = User.objects.filter( Q(club__room=port.room) | Q(adherent__room=port.room) ) if not room_user: - return (sw_name, room, u'Chambre non cotisante -> Web redirect', None, False) + return ( + sw_name, + room, + u'Chambre non cotisante -> Web redirect', + None, + False + ) for user in room_user: - if not user.has_access(): - return (sw_name, room, u'Chambre resident desactive -> Web redirect', None, False) + if user.is_ban() or user.state != User.STATE_ACTIVE: + return ( + sw_name, + room, + u'Utilisateur banni ou désactivé -> Web redirect', + None, + False + ) + elif not (user.is_connected() or user.is_whitelisted()): + return ( + sw_name, + room, + u'Utilisateur non cotisant', + RadiusOption('non_member_vlan').vlan_id, + RadiusOption('non_member')!= RadiusOption.REJECT + ) # else: user OK, on passe à la verif MAC - # Si on fait de l'auth par mac, on cherche l'interface via sa mac dans la bdd + # Si on fait de l'auth par mac, on cherche l'interface + # via sa mac dans la bdd if port_profile.radius_mode == 'COMMON' or port_profile.radius_mode == 'STRICT': # Authentification par mac interface = (Interface.objects @@ -428,38 +483,67 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, .first()) if not interface: room = port.room - # 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, True) - # On rejette pour basculer sur du webauth + # 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. else: - return (sw_name, room, u'Machine Inconnue -> Web redirect', None, False) + return ( + sw_name, + "", + u'Machine inconnue', + RadiusOption('unknown_machine_vlan').vlan_id, + RadiusOption('unknown_machine')!= RadiusOption.REJECT + ) - # L'interface a été trouvée, on vérifie qu'elle est active, sinon on reject + # 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 interface.machine.user.is_ban(): + return ( + sw_name, + room, + u'Adherent banni', + RadiusOption('banned_vlan').vlan_id, + RadiusOption('banned')!= RadiusOption.REJECT + ) if not interface.is_active: - return (sw_name, - room, - u'Machine non active / adherent non cotisant', - VLAN_NOK, - True) - ## Si on choisi de placer les machines sur le vlan correspondant à leur type : - if RADIUS_POLICY == 'MACHINE': + return ( + sw_name, + room, + u'Machine non active / adherent non cotisant', + RadiusOption('non_member_vlan').vlan_id, + RadiusOption('non_member')!= RadiusOption.REJECT + ) + # Si on choisi de placer les machines sur le vlan + # correspondant à leur type : + if RadiusOption.get_cached_value('radius_general_policy') == 'MACHINE': DECISION_VLAN = interface.type.ip_type.vlan.vlan_id if not interface.ipv4: interface.assign_ipv4() - return (sw_name, - room, - u"Ok, Reassignation de l'ipv4" + extra_log, - DECISION_VLAN, - True) + return ( + sw_name, + room, + u"Ok, Reassignation de l'ipv4" + extra_log, + DECISION_VLAN, + True + ) else: - return (sw_name, - room, - u'Machine OK' + extra_log, - DECISION_VLAN, - True) + return ( + sw_name, + room, + u'Machine OK' + extra_log, + DECISION_VLAN, + True + ) diff --git a/preferences/forms.py b/preferences/forms.py index 2f90927f..1126b399 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -42,6 +42,7 @@ from .models import ( Reminder, RadiusKey, SwitchManagementCred, + RadiusOption, ) from topologie.models import Switch @@ -229,6 +230,13 @@ class EditHomeOptionForm(ModelForm): self.fields['twitter_account_name'].label = _("Twitter account name") +class EditRadiusOptionForm(ModelForm): + """Edition forms for Radius options""" + class Meta: + model = RadiusOption + fields = '__all__' + + class ServiceForm(ModelForm): """Edition, ajout de services sur la page d'accueil""" class Meta: diff --git a/preferences/migrations/0055_generaloption_main_site_url.py b/preferences/migrations/0055_generaloption_main_site_url.py index 71ea9852..655c0b07 100644 --- a/preferences/migrations/0055_generaloption_main_site_url.py +++ b/preferences/migrations/0055_generaloption_main_site_url.py @@ -8,7 +8,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('preferences', '0054_merge_20181025_1258'), + ('preferences', '0053_optionaluser_self_change_room'), ] operations = [ diff --git a/preferences/migrations/0056_radiusoption.py b/preferences/migrations/0056_radiusoption.py new file mode 100644 index 00000000..e329f598 --- /dev/null +++ b/preferences/migrations/0056_radiusoption.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-10-13 14:29 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import re2o.mixins + + +def create_radius_policy(apps, schema_editor): + OptionalTopologie = apps.get_model('preferences', 'OptionalTopologie') + RadiusOption = apps.get_model('preferences', 'RadiusOption') + + option,_ = OptionalTopologie.objects.get_or_create() + + radius_option = RadiusOption() + radius_option.radius_general_policy = option.radius_general_policy + radius_option.vlan_decision_ok = option.vlan_decision_ok + + radius_option.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0095_auto_20180919_2225'), + ('preferences', '0055_generaloption_main_site_url'), + ] + + operations = [ + migrations.CreateModel( + name='RadiusOption', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('radius_general_policy', models.CharField(choices=[('MACHINE', "On the IP range's VLAN of the machine"), ('DEFINED', "Preset in 'VLAN for machines accepted by RADIUS'")], default='DEFINED', max_length=32)), + ], + options={ + 'verbose_name': 'radius policies', + }, + bases=(re2o.mixins.AclMixin, models.Model), + ), + migrations.AddField( + model_name='radiusoption', + name='banned_vlan', + field=models.ForeignKey(blank=True, help_text='Vlan for banned if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='banned_vlan', to='machines.Vlan', verbose_name='Banned Vlan'), + ), + migrations.AddField( + model_name='radiusoption', + name='non_member_vlan', + field=models.ForeignKey(blank=True, help_text='Vlan for non members if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='non_member_vlan', to='machines.Vlan', verbose_name='Non member Vlan'), + ), + migrations.AddField( + model_name='radiusoption', + name='unknown_machine_vlan', + field=models.ForeignKey(blank=True, help_text='Vlan for unknown machines if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_machine_vlan', to='machines.Vlan', verbose_name='Unknown machine Vlan'), + ), + migrations.AddField( + model_name='radiusoption', + name='unknown_port_vlan', + field=models.ForeignKey(blank=True, help_text='Vlan for unknown ports if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_port_vlan', to='machines.Vlan', verbose_name='Unknown port Vlan'), + ), + migrations.AddField( + model_name='radiusoption', + name='unknown_room_vlan', + field=models.ForeignKey(blank=True, help_text='Vlan for unknown room if not rejected.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='unknown_room_vlan', to='machines.Vlan', verbose_name='Unknown room Vlan'), + ), + migrations.AddField( + model_name='radiusoption', + name='banned', + field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for banned users.'), + ), + migrations.AddField( + model_name='radiusoption', + name='non_member', + field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy non member users.'), + ), + migrations.AddField( + model_name='radiusoption', + name='unknown_machine', + field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown machines'), + ), + migrations.AddField( + model_name='radiusoption', + name='unknown_port', + field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown machines'), + ), + migrations.AddField( + model_name='radiusoption', + name='unknown_room', + field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for machine connecting from unregistered room (relevant on ports with STRICT radius mode)'), + ), + migrations.AddField( + model_name='radiusoption', + name='vlan_decision_ok', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vlan_ok_option', to='machines.Vlan'), + ), + + migrations.RunPython(create_radius_policy), + migrations.RemoveField( + model_name='optionaltopologie', + name='radius_general_policy', + ), + migrations.RemoveField( + model_name='optionaltopologie', + name='vlan_decision_nok', + ), + migrations.RemoveField( + model_name='optionaltopologie', + name='vlan_decision_ok', + ), + ] diff --git a/preferences/migrations/0057_auto_20181204_0757.py b/preferences/migrations/0057_auto_20181204_0757.py new file mode 100644 index 00000000..ba4e1a6f --- /dev/null +++ b/preferences/migrations/0057_auto_20181204_0757.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-12-04 13:57 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0056_radiusoption'), + ] + + operations = [ + migrations.AlterField( + model_name='radiusoption', + name='unknown_port', + field=models.CharField(choices=[('REJECT', 'Reject the machine'), ('SET_VLAN', 'Place the machine on the VLAN')], default='REJECT', max_length=32, verbose_name='Policy for unknown port'), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index 43ff7580..4644aa1c 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -199,25 +199,6 @@ class OptionalTopologie(AclMixin, PreferencesModel): ('tftp', 'tftp'), ) - radius_general_policy = models.CharField( - max_length=32, - choices=CHOICE_RADIUS, - default='DEFINED' - ) - vlan_decision_ok = models.OneToOneField( - 'machines.Vlan', - on_delete=models.PROTECT, - related_name='decision_ok', - blank=True, - null=True - ) - vlan_decision_nok = models.OneToOneField( - 'machines.Vlan', - on_delete=models.PROTECT, - related_name='decision_nok', - blank=True, - null=True - ) switchs_web_management = models.BooleanField( default=False, help_text="Web management, activé si provision automatique" @@ -309,7 +290,6 @@ class OptionalTopologie(AclMixin, PreferencesModel): """Return true if all settings are ok : switchs on automatic provision, ip_type""" return bool(self.provisioned_switchs and self.switchs_ip_type and SwitchManagementCred.objects.filter(default_switch=True).exists() and self.switchs_management_interface_ip and bool(self.switchs_provision != 'sftp' or self.switchs_management_sftp_creds)) - class Meta: permissions = ( ("view_optionaltopologie", _("Can view the topology options")), @@ -588,3 +568,122 @@ class MailMessageOption(AclMixin, models.Model): ) verbose_name = _("email message options") + +class RadiusOption(AclMixin, PreferencesModel): + class Meta: + verbose_name = _("radius policies") + + MACHINE = 'MACHINE' + DEFINED = 'DEFINED' + CHOICE_RADIUS = ( + (MACHINE, _("On the IP range's VLAN of the machine")), + (DEFINED, _("Preset in 'VLAN for machines accepted by RADIUS'")), + ) + REJECT = 'REJECT' + SET_VLAN = 'SET_VLAN' + CHOICE_POLICY = ( + (REJECT, _('Reject the machine')), + (SET_VLAN, _('Place the machine on the VLAN')) + ) + radius_general_policy = models.CharField( + max_length=32, + choices=CHOICE_RADIUS, + default='DEFINED' + ) + unknown_machine = models.CharField( + max_length=32, + choices=CHOICE_POLICY, + default=REJECT, + verbose_name=_("Policy for unknown machines"), + ) + unknown_machine_vlan = models.ForeignKey( + 'machines.Vlan', + on_delete=models.PROTECT, + related_name='unknown_machine_vlan', + blank=True, + null=True, + verbose_name=_('Unknown machine Vlan'), + help_text=_( + 'Vlan for unknown machines if not rejected.' + ) + ) + unknown_port = models.CharField( + max_length=32, + choices=CHOICE_POLICY, + default=REJECT, + verbose_name=_("Policy for unknown port"), + ) + unknown_port_vlan = models.ForeignKey( + 'machines.Vlan', + on_delete=models.PROTECT, + related_name='unknown_port_vlan', + blank=True, + null=True, + verbose_name=_('Unknown port Vlan'), + help_text=_( + 'Vlan for unknown ports if not rejected.' + ) + ) + unknown_room = models.CharField( + max_length=32, + choices=CHOICE_POLICY, + default=REJECT, + verbose_name=_( + "Policy for machine connecting from " + "unregistered room (relevant on ports with STRICT " + "radius mode)" + ), + ) + unknown_room_vlan = models.ForeignKey( + 'machines.Vlan', + related_name='unknown_room_vlan', + on_delete=models.PROTECT, + blank=True, + null=True, + verbose_name=_('Unknown room Vlan'), + help_text=_( + 'Vlan for unknown room if not rejected.' + ) + ) + non_member = models.CharField( + max_length=32, + choices=CHOICE_POLICY, + default=REJECT, + verbose_name=_("Policy non member users."), + ) + non_member_vlan = models.ForeignKey( + 'machines.Vlan', + related_name='non_member_vlan', + on_delete=models.PROTECT, + blank=True, + null=True, + verbose_name=_('Non member Vlan'), + help_text=_( + 'Vlan for non members if not rejected.' + ) + ) + banned = models.CharField( + max_length=32, + choices=CHOICE_POLICY, + default=REJECT, + verbose_name=_("Policy for banned users."), + ) + banned_vlan = models.ForeignKey( + 'machines.Vlan', + related_name='banned_vlan', + on_delete=models.PROTECT, + blank=True, + null=True, + verbose_name=_('Banned Vlan'), + help_text=_( + 'Vlan for banned if not rejected.' + ) + ) + vlan_decision_ok = models.OneToOneField( + 'machines.Vlan', + on_delete=models.PROTECT, + related_name='vlan_ok_option', + blank=True, + null=True + ) + diff --git a/preferences/templates/preferences/aff_radiusoptions.html b/preferences/templates/preferences/aff_radiusoptions.html new file mode 100644 index 00000000..17e2a869 --- /dev/null +++ b/preferences/templates/preferences/aff_radiusoptions.html @@ -0,0 +1,96 @@ +{% comment %} +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. + +Copyright © 2018 Hugo Levy-Falk + +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. +{% endcomment %} +{% load i18n %} +{% load acl %} +{% load logs_extra %} + + + + + + + + + + + +
{% trans "General policy for VLAN setting" %}{{ radiusoptions.radius_general_policy }}{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
{% trans "VLAN for machines accepted by RADIUS" %}Vlan {{ radiusoptions.vlan_decision_ok }}
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans "Situation" %}{% trans "Behavior" %}
{% trans "Unknown machine" %} + {% if radiusoptions.unknown_machine == 'REJECT' %} + {% trans "Reject" %} + {% else %} + Vlan {{ radiusoptions.unknown_machine_vlan }} + {% endif %} +
{% trans "Unknown port" %} + {% if radiusoptions.unknown_port == 'REJECT' %} + {% trans "Reject" %} + {% else %} + Vlan {{ radiusoptions.unknown_port_vlan }} + {% endif %} +
{% trans "Unknown room" %} + {% if radiusoptions.unknown_room == 'REJECT' %} + {% trans "Reject" %} + {% else %} + Vlan {{ radiusoptions.unknown_room_vlan }} + {% endif %} +
{% trans "Non member" %} + {% if radiusoptions.non_member == 'REJECT' %} + {% trans "Reject" %} + {% else %} + Vlan {{ radiusoptions.non_member_vlan }} + {% endif %} +
{% trans "Banned user" %} + {% if radiusoptions.unknown_port == 'REJECT' %} + {% trans "Reject" %} + {% else %} + Vlan {{ radiusoptions.banned_vlan }} + {% endif %} +
+ diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index 3fde911d..0e34d6e9 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -32,312 +32,323 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block content %}
- -
-
-

+ +

+
- - {% trans "Edit" %} +
+ + + {% trans "Edit" %} -

+

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Website name" %}{{ generaloptions.site_name }}{% trans "Email address for automatic emailing" %}{{ generaloptions.email_from }}
{% trans "Number of results displayed when searching" %}{{ generaloptions.search_display_page }}{% trans "Number of items per page (standard size)" %}{{ generaloptions.pagination_number }}
{% trans "Number of items per page (large size)" %}{{ generaloptions.pagination_large_number }}{% trans "Time before expiration of the reset password link (in hours)" %}{{ generaloptions.req_expire_hrs }}
{% trans "General message displayed on the website" %}{{ generaloptions.general_message }}{% trans "Main site url" %}{{ generaloptions.main_site_url }}
{% trans "Summary of the General Terms of Use" %}{{ generaloptions.GTU_sum_up }}{% trans "General Terms of Use" %}{{ generaloptions.GTU }} -
- - - - - - - - - - - -
{% trans "Local email accounts enabled" %}{{ useroptions.local_email_accounts_enabled|tick }}{% trans "Local email domain" %}{{ useroptions.local_email_domain }}
{% trans "Maximum number of email aliases allowed" %}{{ useroptions.max_email_address }}
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans "Website name" %}{{ generaloptions.site_name }}{% trans "Email address for automatic emailing" %}{{ generaloptions.email_from }}
{% trans "Number of results displayed when searching" %}{{ generaloptions.search_display_page }}{% trans "Number of items per page (standard size)" %}{{ generaloptions.pagination_number }}
{% trans "Number of items per page (large size)" %}{{ generaloptions.pagination_large_number }}{% trans "Time before expiration of the reset password link (in hours)" %}{{ generaloptions.req_expire_hrs }}
{% trans "General message displayed on the website" %}{{ generaloptions.general_message }}{% trans "Main site url" %}{{ generaloptions.main_site_url }}
{% trans "Summary of the General Terms of Use" %}{{ generaloptions.GTU_sum_up }}{% trans "General Terms of Use" %}{{ generaloptions.GTU }} +
+ + + + + + + + + + + +
{% trans "Local email accounts enabled" %}{{ useroptions.local_email_accounts_enabled|tick }}{% trans "Local email domain" %}{{ useroptions.local_email_domain }}
{% trans "Maximum number of email aliases allowed" %}{{ useroptions.max_email_address }}
+
+ -
-
-

- {% trans "User preferences" %} -

-
-
+
+ +
-

- - - {% trans "Edit" %} - -

+

+ + + {% trans "Edit" %} + +

- - - - - - - - - - - - - +
{% trans "Creation of members by everyone" %}{{ useroptions.all_can_create_adherent|tick }}{% trans "Creation of clubs by everyone" %}{{ useroptions.all_can_create_club|tick }}
{% trans "Self registration" %}{{ useroptions.self_adhesion|tick }}{% trans "Delete not yet active users after" %}{{ useroptions.delete_notyetactive }} days
+ + + + + + + + + + + +
{% trans "Creation of members by everyone" %}{{ useroptions.all_can_create_adherent|tick }}{% trans "Creation of clubs by everyone" %}{{ useroptions.all_can_create_club|tick }}
{% trans "Self registration" %}{{ useroptions.self_adhesion|tick }}{% trans "Delete not yet active users after" %}{{ useroptions.delete_notyetactive }} days

{% trans "Users general permissions" %}

- - - - - - - - - - - - - - - - -
{% trans "Default shell for users" %}{{ useroptions.shell_default }}{% trans "Users can edit their shell" %}{{ useroptions.self_change_shell|tick }}
{% trans "Users can edit their room" %}{{ useroptions.self_change_room|tick }}{% trans "Telephone number required" %}{{ useroptions.is_tel_mandatory|tick }}
{% trans "GPG fingerprint field" %}{{ useroptions.gpg_fingerprint|tick }}
-
+ + {% trans "Default shell for users" %} + {{ useroptions.shell_default }} + {% trans "Users can edit their shell" %} + {{ useroptions.self_change_shell|tick }} + + + {% trans "Users can edit their room" %} + {{ useroptions.self_change_room|tick }} + {% trans "Telephone number required" %} + {{ useroptions.is_tel_mandatory|tick }} + + + {% trans "GPG fingerprint field" %} + {{ useroptions.gpg_fingerprint|tick }} + +
- -
- +
-
+
+ - - - {% trans "Edit" %} - -

- - - - - - - - - - - - - - - - - -
{% trans "Password per machine" %}{{ machineoptions.password_machine|tick }}{% trans "Maximum number of interfaces allowed for a standard user" %}{{ machineoptions.max_lambdauser_interfaces }}
{% trans "Maximum number of DNS aliases allowed for a standard user" %}{{ machineoptions.max_lambdauser_aliases }}{% trans "IPv6 support" %}{{ machineoptions.ipv6_mode }}
{% trans "Creation of machines" %}{{ machineoptions.create_machine|tick }}
-
-
+
-
- -
- - + {% trans "Edit" %}

- - - - - - - - - - - - - - - - - -
{% trans "General policy for VLAN setting" %}{{ topologieoptions.radius_general_policy }}{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
{% trans "VLAN for machines accepted by RADIUS" %}{{ topologieoptions.vlan_decision_ok }}{% trans "VLAN for machines rejected by RADIUS" %}{{ topologieoptions.vlan_decision_nok }}
Placement sur ce vlan par default en cas de rejet{{ topologieoptions.vlan_decision_nok }}
- -

Clef radius

- {% can_create RadiusKey%} - Ajouter une clef radius - {% acl_end %} - {% include "preferences/aff_radiuskey.html" with radiuskey_list=radiuskey_list %} - -
-
- -
- -
- - - - {% trans "Edit" %} - -

- - - - - - - -
Web management, activé si provision automatique{{ topologieoptions.switchs_web_management }}Rest management, activé si provision auto{{ topologieoptions.switchs_rest_management }}
+ + {% trans "Password per machine" %} + {{ machineoptions.password_machine|tick }} + {% trans "Maximum number of interfaces allowed for a standard user" %} + {{ machineoptions.max_lambdauser_interfaces }} + + + {% trans "Maximum number of DNS aliases allowed for a standard user" %} + {{ machineoptions.max_lambdauser_aliases }} + {% trans "IPv6 support" %} + {{ machineoptions.ipv6_mode }} + + + {% trans "Creation of machines" %} + {{ machineoptions.create_machine|tick }} + + +
+
+ +
+ +
+ + + + {% trans "Edit" %} + +

+ + + + + + + + + + + + + + + + + +
{% trans "General policy for VLAN setting" %}{{ topologieoptions.radius_general_policy }}{% trans "This setting defines the VLAN policy after acceptance by RADIUS: either on the IP range's VLAN of the machine, or a VLAN preset in 'VLAN for machines accepted by RADIUS'" %}
{% trans "VLAN for machines accepted by RADIUS" %}{{ topologieoptions.vlan_decision_ok }}{% trans "VLAN for machines rejected by RADIUS" %}{{ topologieoptions.vlan_decision_nok }}
{% trans "VLAN for non members machines" %}{{ topologieoptions.vlan_non_member }}
+ +

Clef radius

+ {% can_create RadiusKey%} + Ajouter une clef radius + {% acl_end %} + {% include "preferences/aff_radiuskey.html" with radiuskey_list=radiuskey_list %} + +
+
+ +
+ +
+ + + + {% trans "Edit" %} + +

+ + + + + + + + +
Web management, activé si provision automatique{{ topologieoptions.switchs_web_management }}Rest management, activé si provision auto{{ topologieoptions.switchs_rest_management }}
-
{% if topologieoptions.provision_switchs_enabled %}Provision de la config des switchs{% else %}Provision de la config des switchs{% endif%}
- - - - - - - - - - - - - - - - - - - - - - - - - -
Switchs configurés automatiquement{{ topologieoptions.provisioned_switchs|join:", " }} {% if topologieoptions.provisioned_switchs %} OK{% else %}Manquant{% endif %}
Plage d'ip de management des switchs{{ topologieoptions.switchs_ip_type }} {% if topologieoptions.switchs_ip_type %} OK{% else %}Manquant{% endif %}
Serveur des config des switchs{{ topologieoptions.switchs_management_interface }} {% if topologieoptions.switchs_management_interface %} - {{ topologieoptions.switchs_management_interface_ip }} OK{% else %}Manquant{% endif %}
Mode de provision des switchs{{ topologieoptions.switchs_provision }}
Mode TFTP OK
Mode SFTP{% if topologieoptions.switchs_management_sftp_creds %} OK{% else %}Creds manquants{% endif %}
+
{% if topologieoptions.provision_switchs_enabled %}Provision de la config des switchs{% else %}Provision de la config des switchs{% endif%}
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Switchs configurés automatiquement{{ topologieoptions.provisioned_switchs|join:", " }} {% if topologieoptions.provisioned_switchs %} OK{% else %}Manquant{% endif %}
Plage d'ip de management des switchs{{ topologieoptions.switchs_ip_type }} {% if topologieoptions.switchs_ip_type %} OK{% else %}Manquant{% endif %}
Serveur des config des switchs{{ topologieoptions.switchs_management_interface }} {% if topologieoptions.switchs_management_interface %} - {{ topologieoptions.switchs_management_interface_ip }} OK{% else %}Manquant{% endif %}
Mode de provision des switchs{{ topologieoptions.switchs_provision }}
Mode TFTP OK
Mode SFTP{% if topologieoptions.switchs_management_sftp_creds %} OK{% else %}Creds manquants{% endif %}
-
Creds de management des switchs
- {% can_create SwitchManagementCred%} - Ajouter un id/mdp de management switch - {% acl_end %} -

-

- {% if switchmanagementcred_list %} OK{% else %}Manquant{% endif %} - {% include "preferences/aff_switchmanagementcred.html" with switchmanagementcred_list=switchmanagementcred_list %} -
-
+
Creds de management des switchs
+ {% can_create SwitchManagementCred%} + Ajouter un id/mdp de management switch + {% acl_end %} +

+

+ {% if switchmanagementcred_list %} OK{% else %}Manquant{% endif %} + {% include "preferences/aff_switchmanagementcred.html" with switchmanagementcred_list=switchmanagementcred_list %} +
+
+
+
+

{% trans "Radius preferences" %}

+
+
+ + + {% trans "Edit" %} + + {% include "preferences/aff_radiusoptions.html" %} +
+
-
+
- {% trans "Edit" %}

- - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Name" %}{{ assooptions.name }}{% trans "SIRET number" %}{{ assooptions.siret }}
{% trans "Address" %}{{ assooptions.adresse1 }}
- {{ assooptions.adresse2 }} -
{% trans "Contact email address" %}{{ assooptions.contact }}
{% trans "Telephone number" %}{{ assooptions.telephone }}{% trans "Usual name" %}{{ assooptions.pseudo }}
{% trans "User object of the organisation" %}{{ assooptions.utilisateur_asso }}{% trans "Description of the organisation" %}{{ assooptions.description|safe }}
+ + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans "Name" %}{{ assooptions.name }}{% trans "SIRET number" %}{{ assooptions.siret }}
{% trans "Address" %}{{ assooptions.adresse1 }}
+ {{ assooptions.adresse2 }} +
{% trans "Contact email address" %}{{ assooptions.contact }}
{% trans "Telephone number" %}{{ assooptions.telephone }}{% trans "Usual name" %}{{ assooptions.pseudo }}
{% trans "User object of the organisation" %}{{ assooptions.utilisateur_asso }}{% trans "Description of the organisation" %}{{ assooptions.description|safe }}
-
- -
+
+ +
+

+ Message pour les mails +

+
@@ -346,61 +357,61 @@ with this program; if not, write to the Free Software Foundation, Inc.,

- - - - - - - - - -
{% trans "Welcome email (in French)" %}{{ mailmessageoptions.welcome_mail_fr|safe }}
{% trans "Welcome email (in English)" %}{{ mailmessageoptions.welcome_mail_en|safe }}
-
-
+ + + + + + + + + +
{% trans "Welcome email (in French)" %}{{ mailmessageoptions.welcome_mail_fr|safe }}
{% trans "Welcome email (in English)" %}{{ mailmessageoptions.welcome_mail_en|safe }}
+ + -
+
- +
{% can_create preferences.Reminder%} - + Ajouter un rappel

{% acl_end %} {% include "preferences/aff_reminder.html" with reminder_list=reminder_list %}
-
+
-
+
{% can_create preferences.Service%} - + {% trans " Add a service" %}

{% acl_end %} {% include "preferences/aff_service.html" with service_list=service_list %} - -
-
-
+
+
+ +
-

- {% trans "List of contact email addresses" %} -

-
-
- +

+ {% trans "List of contact email addresses" %} +

+
+
+ {% can_create preferences.MailContact %} {% trans "Add an address" %} {% acl_end %} @@ -408,12 +419,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,

{% include "preferences/aff_mailcontact.html" with mailcontact_list=mailcontact_list %}
-
+ -
+
@@ -423,20 +434,20 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Edit" %}

- - - - - - - - - - - -
{% trans "Twitter account URL" %}{{ homeoptions.twitter_url }}{% trans "Twitter account name" %}{{ homeoptions.twitter_account_name }}
{% trans "Facebook account URL" %}{{ homeoptions.facebook_url }}
-
+ + + + + + + + + + + +
{% trans "Twitter account URL" %}{{ homeoptions.twitter_url }}{% trans "Twitter account name" %}{{ homeoptions.twitter_account_name }}
{% trans "Facebook account URL" %}{{ homeoptions.facebook_url }}
+
{% endblock %} diff --git a/preferences/templates/preferences/edit_preferences.html b/preferences/templates/preferences/edit_preferences.html index a1540f33..c3dd4652 100644 --- a/preferences/templates/preferences/edit_preferences.html +++ b/preferences/templates/preferences/edit_preferences.html @@ -37,6 +37,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% csrf_token %} {% massive_bootstrap_form options 'utilisateur_asso,automatic_provision_switchs' %} + {% if formset %} + {{ formset.management_form }} + {% for f in formset %} + {% bootstrap_form f %} + {% endfor %} + {% endif %} {% trans "Edit" as tr_edit %} {% bootstrap_button tr_edit button_type="submit" icon='ok' button_class='btn-success' %}
diff --git a/preferences/urls.py b/preferences/urls.py index 63ca6a39..30163868 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -66,6 +66,11 @@ urlpatterns = [ views.edit_options, name='edit-options' ), + url( + r'^edit_options/(?P
RadiusOption)$', + views.edit_options, + name='edit-options' + ), url(r'^add_service/$', views.add_service, name='add-service'), url( r'^edit_service/(?P[0-9]+)$', diff --git a/preferences/views.py b/preferences/views.py index ee81ae89..586be60f 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -62,7 +62,8 @@ from .models import ( HomeOption, Reminder, RadiusKey, - SwitchManagementCred + SwitchManagementCred, + RadiusOption, ) from . import models from . import forms @@ -86,6 +87,7 @@ def display_options(request): reminder_list = Reminder.objects.all() radiuskey_list = RadiusKey.objects.all() switchmanagementcred_list = SwitchManagementCred.objects.all() + radiusoptions, _ = RadiusOption.objects.get_or_create() return form({ 'useroptions': useroptions, 'machineoptions': machineoptions, @@ -98,7 +100,8 @@ def display_options(request): 'mailcontact_list': mailcontact_list, 'reminder_list': reminder_list, 'radiuskey_list' : radiuskey_list, - 'switchmanagementcred_list': switchmanagementcred_list, + 'switchmanagementcred_list': switchmanagementcred_list, + 'radiusoptions' : radiusoptions, }, 'preferences/display_preferences.html', request) @@ -134,7 +137,9 @@ def edit_options(request, section): messages.success(request, _("The preferences were edited.")) return redirect(reverse('preferences:display-options')) return form( - {'options': options}, + { + 'options': options, + }, 'preferences/edit_preferences.html', request ) diff --git a/users/forms.py b/users/forms.py index b96e3ad3..70d8798b 100644 --- a/users/forms.py +++ b/users/forms.py @@ -384,8 +384,8 @@ class AdherentCreationForm(AdherentForm): # Checkbox for GTU gtu_check = forms.BooleanField(required=True) - gtu_check.label = mark_safe("{} {}{}".format( - _("I commit to accept the"), GeneralOption.get_cached_value('GTU'), _("General Terms of Use"), _("."))) + #gtu_check.label = mark_safe("{} {}{}".format( + # _("I commit to accept the"), GeneralOption.get_cached_value('GTU'), _("General Terms of Use"), _("."))) def __init__(self, *args, **kwargs): super(AdherentCreationForm, self).__init__(*args, **kwargs)