8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-22 03:13:12 +00:00

Gestion de la clef radius, et serialisation

This commit is contained in:
Gabriel Detraz 2018-07-11 01:07:31 +02:00 committed by grizzly
parent 282ea9b2c6
commit b9dbce8ccc
12 changed files with 368 additions and 6 deletions

View file

@ -751,7 +751,7 @@ class SwitchPortSerializer(serializers.ModelSerializer):
model = topologie.Switch model = topologie.Switch
fields = ('short_name', 'model', 'switchbay', 'ports', 'ipv4', 'ipv6', fields = ('short_name', 'model', 'switchbay', 'ports', 'ipv4', 'ipv6',
'subnet', 'subnet6', 'automatic_provision', 'rest_enabled', 'subnet', 'subnet6', 'automatic_provision', 'rest_enabled',
'web_management_enabled') 'web_management_enabled', 'get_radius_key_value')
# LOCAL EMAILS # LOCAL EMAILS

View file

@ -37,7 +37,8 @@ from .models import (
MailContact, MailContact,
AssoOption, AssoOption,
MailMessageOption, MailMessageOption,
HomeOption HomeOption,
RadiusKey
) )
@ -86,6 +87,11 @@ class HomeOptionAdmin(VersionAdmin):
pass pass
class RadiusKeyAdmin(VersionAdmin):
"""Class radiuskey"""
pass
admin.site.register(OptionalUser, OptionalUserAdmin) admin.site.register(OptionalUser, OptionalUserAdmin)
admin.site.register(OptionalMachine, OptionalMachineAdmin) admin.site.register(OptionalMachine, OptionalMachineAdmin)
admin.site.register(OptionalTopologie, OptionalTopologieAdmin) admin.site.register(OptionalTopologie, OptionalTopologieAdmin)
@ -93,5 +99,7 @@ admin.site.register(GeneralOption, GeneralOptionAdmin)
admin.site.register(HomeOption, HomeOptionAdmin) admin.site.register(HomeOption, HomeOptionAdmin)
admin.site.register(Service, ServiceAdmin) admin.site.register(Service, ServiceAdmin)
admin.site.register(MailContact, MailContactAdmin) admin.site.register(MailContact, MailContactAdmin)
admin.site.register(Reminder, ReminderAdmin)
admin.site.register(RadiusKey, RadiusKeyAdmin)
admin.site.register(AssoOption, AssoOptionAdmin) admin.site.register(AssoOption, AssoOptionAdmin)
admin.site.register(MailMessageOption, MailMessageOptionAdmin) admin.site.register(MailMessageOption, MailMessageOptionAdmin)

View file

@ -39,6 +39,8 @@ from .models import (
HomeOption, HomeOption,
Service, Service,
MailContact MailContact
Reminder,
RadiusKey
) )
@ -242,8 +244,33 @@ class DelServiceForm(Form):
else: else:
self.fields['services'].queryset = Service.objects.all() self.fields['services'].queryset = Service.objects.all()
class MailContactForm(FormRevMixin, ModelForm):
"""Edit and add contact email adress""" class RadiusKeyForm(FormRevMixin, ModelForm):
"""Edition, ajout de clef radius"""
members = forms.ModelMultipleChoiceField(
Switch.objects.all(),
required=False
)
class Meta:
model = RadiusKey
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(RadiusKeyForm, self).__init__(*args, prefix=prefix, **kwargs)
instance = kwargs.get('instance', None)
if instance:
self.initial['members'] = Switch.objects.filter(radius_key=instance)
def save(self, commit=True):
instance = super().save(commit)
instance.switch_set = self.cleaned_data['members']
return instance
class MailContactForm(ModelForm):
"""Edition, ajout d'adresse de contact"""
class Meta: class Meta:
model = MailContact model = MailContact
fields = '__all__' fields = '__all__'

View file

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-10 22:15
from __future__ import unicode_literals
from django.db import migrations, models
import re2o.aes_field
import re2o.mixins
class Migration(migrations.Migration):
dependencies = [
('preferences', '0046_merge_20180710_1533'),
]
operations = [
migrations.CreateModel(
name='RadiusKey',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('radius_key', re2o.aes_field.AESEncryptedField(help_text='Clef radius', max_length=255)),
('comment', models.CharField(blank=True, help_text='Commentaire de cette clef', max_length=255, null=True)),
('default_switch', models.BooleanField(default=True, help_text='Clef par défaut des switchs', unique=True)),
],
options={
'permissions': (('view_radiuskey', 'Peut voir un objet radiuskey'),),
},
bases=(re2o.mixins.AclMixin, models.Model),
),
migrations.AlterField(
model_name='optionaluser',
name='gpg_fingerprint',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='optionaluser',
name='is_tel_mandatory',
field=models.BooleanField(default=True),
),
]

View file

@ -35,6 +35,11 @@ from django.utils.translation import ugettext_lazy as _
import machines.models import machines.models
from re2o.mixins import AclMixin from re2o.mixins import AclMixin
<<<<<<< HEAD
=======
from re2o.aes_field import AESEncryptedField
from datetime import timedelta
>>>>>>> 3d881c4f... Gestion de la clef radius, et serialisation
class PreferencesModel(models.Model): class PreferencesModel(models.Model):
@ -240,6 +245,63 @@ def optionaltopologie_post_save(**kwargs):
topologie_pref.set_in_cache() topologie_pref.set_in_cache()
class RadiusKey(AclMixin, models.Model):
"""Class of a radius key"""
radius_key = AESEncryptedField(
max_length=255,
help_text="Clef radius"
)
comment = models.CharField(
max_length=255,
null=True,
blank=True,
help_text="Commentaire de cette clef"
)
default_switch = models.BooleanField(
default=True,
unique=True,
help_text= "Clef par défaut des switchs"
)
class Meta:
permissions = (
("view_radiuskey", "Peut voir un objet radiuskey"),
)
class Reminder(AclMixin, models.Model):
"""Options pour les mails de notification de fin d'adhésion.
Days: liste des nombres de jours pour lesquells un mail est envoyé
optionalMessage: message additionel pour le mail
"""
PRETTY_NAME="Options pour le mail de fin d'adhésion"
days = models.IntegerField(
default=7,
unique=True,
help_text="Délais entre le mail et la fin d'adhésion"
)
message = models.CharField(
max_length=255,
default="",
null=True,
blank=True,
help_text="Message affiché spécifiquement pour ce rappel"
)
class Meta:
permissions = (
("view_reminder", "Peut voir un objet reminder"),
)
def users_to_remind(self):
from re2o.utils import all_has_access
date = timezone.now().replace(minute=0,hour=0)
futur_date = date + timedelta(days=self.days)
users = all_has_access(futur_date).exclude(pk__in = all_has_access(futur_date + timedelta(days=1)))
return users
class GeneralOption(AclMixin, PreferencesModel): class GeneralOption(AclMixin, PreferencesModel):
"""Options générales : nombre de resultats par page, nom du site, """Options générales : nombre de resultats par page, nom du site,
temps les liens sont valides""" temps les liens sont valides"""

View file

@ -0,0 +1,49 @@
{% 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 © 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.
{% endcomment %}
{% load acl %}
<table class="table table-striped">
<thead>
<tr>
<th>Clef</th>
<th>Commentaire</th>
<th>Clef par default des switchs</th>
<th></th>
<th></th>
</tr>
</thead>
{% for radiuskey in radiuskey_list %}
<tr>
<td>{{ radiuskey.radius_key }}</td>
<td>{{ radiuskey.comment }}</td>
<td>{{ radiuskey.default_switch }}</td>
<td class="text-right">
{% can_edit radiuskey %}
{% include 'buttons/edit.html' with href='preferences:edit-radiuskey' id=radiuskey.id %}
{% acl_end %}
{% include 'buttons/history.html' with href='preferences:history' name='radiuskey' id=radiuskey.id %}
</td>
</tr>
{% endfor %}
</table>

View file

@ -118,6 +118,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<th>{% trans "VLAN for machines rejected by RADIUS" %}</th> <th>{% trans "VLAN for machines rejected by RADIUS" %}</th>
<td>{{ topologieoptions.vlan_decision_nok }}</td> <td>{{ topologieoptions.vlan_decision_nok }}</td>
</tr> </tr>
<tr>
<th>Placement sur ce vlan par default en cas de rejet</th>
<td>{{ topologieoptions.vlan_decision_nok }}</td>
</tr>
</table>
<h5>Configuration des switches</h5>
<table class="table table-striped">
<tr>
<th>Web management, activé si provision automatique</th>
<td>{{ topologieoptions.switchs_web_management }}</td>
<th>Rest management, activé si provision auto</th>
<td>{{ topologieoptions.switchs_rest_management }}</td>
</tr>
<tr>
<th>Plage d'ip de management des switchs</th>
<td>{{ topologieoptions.switchs_ip_type }}</td>
</tr>
</table>
<h5>Clef radius</h5>
{% can_create RadiusKey%}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-radiuskey' %}"><i class="fa fa-plus"></i> Ajouter une clef radius</a>
{% acl_end %}
{% include "preferences/aff_radiuskey.html" with radiuskey_list=radiuskey_list %}
<h5>{% if topologieoptions.provisioned_switchs %}<span class="label label-success">Provision de la config des switchs{% else %}<span class="label label-danger">Provision de la config des switchs{% endif%}</span></h5>
<table class="table table-striped">
<tr>
<th>Switchs configurés automatiquement</th>
<td>{{ topologieoptions.provisioned_switchs|join:", " }}</td>
</tr>
</table> </table>
<h4>{% trans "General preferences" %}</h4> <h4>{% trans "General preferences" %}</h4>
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'GeneralOption' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'GeneralOption' %}">

View file

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %} {% load bootstrap3 %}
{% load i18n %} {% load i18n %}
{% load massive_bootstrap_form %}
{% block title %}{% trans "Preferences" %}{% endblock %} {% block title %}{% trans "Preferences" %}{% endblock %}
@ -37,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<form class="form" method="post" enctype="multipart/form-data"> <form class="form" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{% if preferenceform %} {% if preferenceform %}
{% bootstrap_form preferenceform %} {% massive_bootstrap_form preferenceform 'members' %}
{% endif %} {% endif %}
{% bootstrap_button action_name button_type="submit" icon='ok' button_class='btn-success' %} {% bootstrap_button action_name button_type="submit" icon='ok' button_class='btn-success' %}
</form> </form>

View file

@ -80,5 +80,19 @@ urlpatterns = [
name='edit-mailcontact' name='edit-mailcontact'
), ),
url(r'^del_mailcontact/$', views.del_mailcontact, name='del-mailcontact'), url(r'^del_mailcontact/$', views.del_mailcontact, name='del-mailcontact'),
url(r'^add_reminder/$', views.add_reminder, name='add-reminder'),
url(
r'^edit_reminder/(?P<reminderid>[0-9]+)$',
views.edit_reminder,
name='edit-reminder'
),
url(r'^del_reminder/$', views.del_reminder, name='del-reminder'),
url(r'^add_radiuskey/$', views.add_radiuskey, name='add-radiuskey'),
url(
r'^edit_radiuskey/(?P<radiuskeyid>[0-9]+)$',
views.edit_radiuskey,
name='edit-radiuskey'
),
url(r'^del_radiuskey/$', views.del_radiuskey, name='del-radiuskey'),
url(r'^$', views.display_options, name='display-options'), url(r'^$', views.display_options, name='display-options'),
] ]

View file

@ -43,8 +43,16 @@ from reversion import revisions as reversion
from re2o.views import form from re2o.views import form
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all from re2o.acl import can_create, can_edit, can_delete_set, can_view_all
<<<<<<< HEAD
from .forms import ( from .forms import (
ServiceForm, DelServiceForm, MailContactForm, DelMailContactForm ServiceForm, DelServiceForm, MailContactForm, DelMailContactForm
=======
from .forms import MailContactForm, DelMailContactForm
from .forms import (
ServiceForm,
ReminderForm,
RadiusKeyForm
>>>>>>> 3d881c4f... Gestion de la clef radius, et serialisation
) )
from .models import ( from .models import (
Service, Service,
@ -55,7 +63,13 @@ from .models import (
MailMessageOption, MailMessageOption,
GeneralOption, GeneralOption,
OptionalTopologie, OptionalTopologie,
<<<<<<< HEAD
HomeOption HomeOption
=======
HomeOption,
Reminder,
RadiusKey
>>>>>>> 3d881c4f... Gestion de la clef radius, et serialisation
) )
from . import models from . import models
from . import forms from . import forms
@ -76,6 +90,11 @@ def display_options(request):
mailmessageoptions, _created = MailMessageOption.objects.get_or_create() mailmessageoptions, _created = MailMessageOption.objects.get_or_create()
service_list = Service.objects.all() service_list = Service.objects.all()
mailcontact_list = MailContact.objects.all() mailcontact_list = MailContact.objects.all()
<<<<<<< HEAD
=======
reminder_list = Reminder.objects.all()
radiuskey_list = RadiusKey.objects.all()
>>>>>>> 3d881c4f... Gestion de la clef radius, et serialisation
return form({ return form({
'useroptions': useroptions, 'useroptions': useroptions,
'machineoptions': machineoptions, 'machineoptions': machineoptions,
@ -85,7 +104,13 @@ def display_options(request):
'homeoptions': homeoptions, 'homeoptions': homeoptions,
'mailmessageoptions': mailmessageoptions, 'mailmessageoptions': mailmessageoptions,
'service_list': service_list, 'service_list': service_list,
<<<<<<< HEAD
'mailcontact_list': mailcontact_list 'mailcontact_list': mailcontact_list
=======
'reminder_list': reminder_list,
'mailcontact_list': mailcontact_list,
'radiuskey_list' : radiuskey_list,
>>>>>>> 3d881c4f... Gestion de la clef radius, et serialisation
}, 'preferences/display_preferences.html', request) }, 'preferences/display_preferences.html', request)
@ -198,6 +223,69 @@ def del_service(request, instances):
@login_required @login_required
<<<<<<< HEAD
=======
@can_delete(Reminder)
def del_reminder(request, reminder_instance, **_kwargs):
"""Destruction d'un reminder"""
if request.method == "POST":
reminder_instance.delete()
messages.success(request, "Le reminder a été détruit")
return redirect(reverse('preferences:display-options'))
return form(
{'objet': reminder_instance, 'objet_name': 'reminder'},
'preferences/delete.html',
request
)
@login_required
@can_create(RadiusKey)
def add_radiuskey(request):
"""Ajout d'une clef radius"""
radiuskey = RadiusKeyForm(request.POST or None)
if radiuskey.is_valid():
radiuskey.save()
messages.success(request, "Cette clef a été ajouté")
return redirect(reverse('preferences:display-options'))
return form(
{'preferenceform': radiuskey, 'action_name': 'Ajouter'},
'preferences/preferences.html',
request
)
@can_edit(RadiusKey)
def edit_radiuskey(request, radiuskey_instance, **_kwargs):
"""Edition des clefs radius"""
radiuskey = RadiusKeyForm(request.POST or None, instance=radiuskey_instance)
if radiuskey.is_valid():
radiuskey.save()
messages.success(request, "Radiuskey modifié")
return redirect(reverse('preferences:display-options'))
return form(
{'preferenceform': radiuskey, 'action_name': 'Editer'},
'preferences/preferences.html',
request
)
@login_required
@can_delete(RadiusKey)
def del_radiuskey(request, radiuskey_instance, **_kwargs):
"""Destruction d'un radiuskey"""
if request.method == "POST":
radiuskey_instance.delete()
messages.success(request, "La radiuskey a été détruite")
return redirect(reverse('preferences:display-options'))
return form(
{'objet': radiuskey_instance, 'objet_name': 'radiuskey'},
'preferences/delete.html',
request
)
@login_required
>>>>>>> 3d881c4f... Gestion de la clef radius, et serialisation
@can_create(MailContact) @can_create(MailContact)
def add_mailcontact(request): def add_mailcontact(request):
"""Add a contact email adress.""" """Add a contact email adress."""

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-10 22:20
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('preferences', '0047_auto_20180711_0015'),
('topologie', '0069_switch_automatic_provision'),
]
operations = [
migrations.AddField(
model_name='switch',
name='radius_key',
field=models.ForeignKey(blank=True, help_text='Clef radius du switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.RadiusKey'),
),
]

View file

@ -49,6 +49,7 @@ from django.db import transaction
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from reversion import revisions as reversion from reversion import revisions as reversion
from preferences.models import OptionalTopologie, RadiusKey
from machines.models import Machine, regen from machines.models import Machine, regen
from re2o.mixins import AclMixin, RevMixin from re2o.mixins import AclMixin, RevMixin
@ -228,6 +229,13 @@ class Switch(AclMixin, Machine):
null=True, null=True,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
) )
radius_key = models.ForeignKey(
'preferences.RadiusKey',
blank=True,
null=True,
on_delete=models.PROTECT,
help_text="Clef radius du switch"
)
class Meta: class Meta:
unique_together = ('stack', 'stack_member_id') unique_together = ('stack', 'stack_member_id')
@ -295,7 +303,18 @@ class Switch(AclMixin, Machine):
@cached_property @cached_property
def get_name(self): def get_name(self):
return self.name or self.main_interface().domain.name return self.name or self.main_interface().domain.name
@cached_property
def get_radius_key(self):
return self.radius_key or RadiusKey.objects.filter(default_switch=True).first()
@cached_property
def get_radius_key_value(self):
if self.get_radius_key:
return self.get_radius_key.radius_key
else:
return None
@cached_property @cached_property
def rest_enabled(self): def rest_enabled(self):
return OptionalTopologie.get_cached_value('switchs_rest_management') or self.automatic_provision return OptionalTopologie.get_cached_value('switchs_rest_management') or self.automatic_provision