Le serveur gitlab sera inaccessible le mercredi 19 février 2020 de 13h à 14h pour une intervention de maintenance programmée.

...
 
Commits (18)
......@@ -40,9 +40,12 @@ from .models import (
Srv,
Nas,
Service,
Role,
OuverturePort,
Ipv6List,
OuverturePortList
OuverturePortList,
SshFingerprint,
SshFprAlgo,
)
......@@ -135,6 +138,20 @@ class ServiceAdmin(VersionAdmin):
""" Admin view of a ServiceAdmin object """
list_display = ('service_type', 'min_time_regen', 'regular_time_regen')
class RoleAdmin(VersionAdmin):
""" Admin view of a RoleAdmin object """
pass
class SshFprAlgoAdmin(VersionAdmin):
""" Admin view of a SshFprAlgo object """
pass
class SshFingerprintAdmin(VersionAdmin):
""" Admin view of a SshFprAlgo object """
pass
admin.site.register(Machine, MachineAdmin)
admin.site.register(MachineType, MachineTypeAdmin)
......@@ -149,8 +166,11 @@ admin.site.register(IpList, IpListAdmin)
admin.site.register(Interface, InterfaceAdmin)
admin.site.register(Domain, DomainAdmin)
admin.site.register(Service, ServiceAdmin)
admin.site.register(Role, RoleAdmin)
admin.site.register(Vlan, VlanAdmin)
admin.site.register(Ipv6List, Ipv6ListAdmin)
admin.site.register(Nas, NasAdmin)
admin.site.register(OuverturePort, OuverturePortAdmin)
admin.site.register(OuverturePortList, OuverturePortListAdmin)
admin.site.register(SshFprAlgo, SshFprAlgoAdmin)
admin.site.register(SshFingerprint, SshFingerprintAdmin)
......@@ -52,6 +52,7 @@ from .models import (
Mx,
Txt,
Ns,
Role,
Service,
Vlan,
Srv,
......@@ -59,6 +60,8 @@ from .models import (
IpType,
OuverturePortList,
Ipv6List,
SshFingerprint,
SshFprAlgo
)
......@@ -260,6 +263,7 @@ class ExtensionForm(FormRevMixin, ModelForm):
self.fields['origin'].label = 'Enregistrement A origin'
self.fields['origin_v6'].label = 'Enregistrement AAAA origin'
self.fields['soa'].label = 'En-tête SOA à utiliser'
self.fielss['mail_extension'].label = 'Utilisable comme extension mail'
class DelExtensionForm(FormRevMixin, Form):
......@@ -467,6 +471,40 @@ class DelNasForm(FormRevMixin, Form):
self.fields['nas'].queryset = Nas.objects.all()
class RoleForm(FormRevMixin, ModelForm):
"""Ajout et edition d'un role"""
class Meta:
model = Role
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(RoleForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['servers'].queryset = (Interface.objects.all()
.select_related(
'domain__extension'
))
class DelRoleForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs service"""
role = forms.ModelMultipleChoiceField(
queryset=Role.objects.none(),
label="Roles actuels",
widget=forms.CheckboxSelectMultiple
)
def __init__(self, *args, **kwargs):
instances = kwargs.pop('instances', None)
super(DelRoleForm, self).__init__(*args, **kwargs)
if instances:
self.fields['role'].queryset = instances
else:
self.fields['role'].queryset = role.objects.all()
class ServiceForm(FormRevMixin, ModelForm):
"""Ajout et edition d'une classe de service : dns, dhcp, etc"""
class Meta:
......@@ -566,3 +604,33 @@ class EditOuverturePortListForm(FormRevMixin, ModelForm):
prefix=prefix,
**kwargs
)
class SshFingerprintForm(FormRevMixin, ModelForm):
"""Edition d'une sshfingerprint"""
class Meta:
model = SshFingerprint
exclude = ('machine',)
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(SshFingerprintForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
class SshFprAlgoForm(FormRevMixin, ModelForm):
"""Edition de la liste des algo pour sshfpr"""
class Meta:
model = SshFprAlgo
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(SshFprAlgoForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-21 20:24
from __future__ import unicode_literals
from django.db import migrations
import macaddress.fields
class Migration(migrations.Migration):
dependencies = [
('machines', '0081_auto_20180521_1413'),
]
operations = [
migrations.AlterField(
model_name='interface',
name='mac_address',
field=macaddress.fields.MACAddressField(integer=False, max_length=17),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-23 14:07
from __future__ import unicode_literals
from django.db import migrations, models
import re2o.mixins
class Migration(migrations.Migration):
dependencies = [
('machines', '0082_auto_20180621_1524'),
]
operations = [
migrations.CreateModel(
name='Role',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('role_type', models.CharField(max_length=255, unique=True)),
('servers', models.ManyToManyField(to='machines.Interface')),
],
options={
'permissions': (('view_role', 'Peut voir un objet service'),),
},
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-23 14:51
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import re2o.mixins
class Migration(migrations.Migration):
dependencies = [
('machines', '0083_role'),
]
operations = [
migrations.CreateModel(
name='SshFingerprint',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hash_entry', models.TextField(max_length=512)),
('comment', models.CharField(blank=True, max_length=255, null=True)),
],
options={
'permissions': (('view_sshfingerprint', 'Peut voir un objet sshfingerprint'),),
},
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model),
),
migrations.CreateModel(
name='SshFprAlgo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(max_length=256)),
],
options={
'permissions': (('view_sshfpralgo', 'Peut voir un algo de chiffrement'),),
},
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model),
),
migrations.AddField(
model_name='sshfingerprint',
name='algo',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.SshFprAlgo'),
),
migrations.AddField(
model_name='sshfingerprint',
name='machine',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='machines.Machine'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-23 16:17
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('machines', '0084_auto_20180623_1651'),
]
operations = [
migrations.AlterField(
model_name='sshfpralgo',
name='name',
field=models.CharField(max_length=256),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-06-24 10:54
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('machines', '0085_auto_20180623_1817'),
]
operations = [
migrations.RenameField(
model_name='sshfingerprint',
old_name='hash_entry',
new_name='pub_key_entry',
),
migrations.AlterField(
model_name='sshfingerprint',
name='comment',
field=models.CharField(blank=True, help_text='Commentaire', max_length=255, null=True),
),
migrations.AlterField(
model_name='sshfingerprint',
name='pub_key_entry',
field=models.TextField(help_text='Clef publique ssh', max_length=2048),
),
]
......@@ -33,6 +33,7 @@ from itertools import chain
from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress
from django.db import models
from django.db.models import Q
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.forms import ValidationError
......@@ -190,6 +191,27 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
"que les vôtres")
return True, None
@cached_property
def short_name(self):
"""Par defaut, renvoie le nom de la première interface
de cette machine"""
return str(self.interface_set.first().domain.name)
@cached_property
def all_short_names(self):
"""Renvoie de manière unique, le nom des interfaces de cette
machine"""
return Domain.objects.filter(
interface_parent__machine=self
).values_list('name', flat=True).distinct()
@cached_property
def all_complete_names(self):
"""Renvoie tous les tls complets de la machine"""
return [str(domain) for domain in Domain.objects.filter(
Q(cname__interface_parent__machine=self) | Q(interface_parent__machine=self)
)]
def __init__(self, *args, **kwargs):
super(Machine, self).__init__(*args, **kwargs)
self.field_permissions = {
......@@ -199,6 +221,60 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
def __str__(self):
return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name)
class SshFingerprint(RevMixin, AclMixin, models.Model):
"""Stockage de la clef ssh publique d'une machine
et calcul de ses hash"""
PRETTY_NAME = "Clef publique ssh"
machine = models.ForeignKey('Machine', on_delete=models.CASCADE)
pub_key_entry = models.TextField(
help_text="Clef publique ssh",
max_length=2048
)
algo = models.ForeignKey(
'SshFprAlgo',
on_delete=models.PROTECT
)
comment = models.CharField(
help_text="Commentaire",
max_length=255,
null=True,
blank=True
)
class Meta:
permissions = (
("view_sshfingerprint", "Peut voir un objet sshfingerprint"),
)
def can_view(self, user_request, *_args, **_kwargs):
return self.machine.can_view(user_request, *_args, **_kwargs)
def can_edit(self, user_request, *args, **kwargs):
return self.machine.can_edit(user_request, *args, **kwargs)
def can_delete(self, user_request, *args, **kwargs):
return self.machine.can_delete(user_request, *args, **kwargs)
def __str__(self):
return str(self.algo) + ' ' + str(self.pub_key_entry) + ' ' + str(self.comment)
class SshFprAlgo(RevMixin, AclMixin, models.Model):
"""Un aglorithme de création de la fingerprint ssh"""
PRETTY_NAME = "Algo de clef ssh"
name = models.CharField(max_length=256)
class Meta:
permissions = (
("view_sshfpralgo", "Peut voir un algo de chiffrement"),
)
def __str__(self):
return str(self.name)
class MachineType(RevMixin, AclMixin, models.Model):
""" Type de machine, relié à un type d'ip, affecté aux interfaces"""
......@@ -285,11 +361,28 @@ class IpType(RevMixin, AclMixin, models.Model):
""" Renvoie une IPSet à partir de l'iptype"""
return IPSet(self.ip_range)
@cached_property
def ip_set_cidrs_as_str(self):
"""Renvoie la liste des cidrs du range en str"""
return [str(ip_range) for ip_range in self.ip_set.iter_cidrs()]
@cached_property
def ip_set_as_str(self):
""" Renvoie une liste des ip en string"""
return [str(x) for x in self.ip_set]
@cached_property
def ip_set_full_info(self):
"""Iter sur les range cidr, et renvoie network, broacast , etc"""
return [
{
'network': str(ip_set.network),
'netmask': str(ip_set.netmask),
'broadcast': str(ip_set.broadcast),
} for ip_set in self.ip_set.iter_cidrs()
]
def ip_objects(self):
""" Renvoie tous les objets ipv4 relié à ce type"""
return IpList.objects.filter(ip_type=self)
......@@ -305,12 +398,9 @@ class IpType(RevMixin, AclMixin, models.Model):
crée les ip une par une. Si elles existent déjà, met à jour le type
associé à l'ip"""
# Creation du range d'ip dans les objets iplist
networks = []
for net in self.ip_range.cidrs():
networks += net.iter_hosts()
ip_obj = [IpList(ip_type=self, ipv4=str(ip)) for ip in networks]
ip_obj = [IpList(ip_type=self, ipv4=str(ip)) for ip in self.ip_range]
listes_ip = IpList.objects.filter(
ipv4__in=[str(ip) for ip in networks]
ipv4__in=[str(ip) for ip in self.ip_range]
)
# Si il n'y a pas d'ip, on les crée
if not listes_ip:
......@@ -543,6 +633,10 @@ class Extension(RevMixin, AclMixin, models.Model):
'SOA',
on_delete=models.CASCADE
)
mail_extension = models.BooleanField(
default=False,
help_text="Determine si l'extension peut être utilisée comme extension mail interne"
)
class Meta:
permissions = (
......@@ -730,7 +824,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
blank=True,
null=True
)
mac_address = MACAddressField(integer=False, unique=True)
mac_address = MACAddressField(integer=False)
machine = models.ForeignKey('Machine', on_delete=models.CASCADE)
type = models.ForeignKey('MachineType', on_delete=models.PROTECT)
details = models.CharField(max_length=255, blank=True)
......@@ -1325,6 +1419,26 @@ class IpList(RevMixin, AclMixin, models.Model):
return self.ipv4
class Role(RevMixin, AclMixin, models.Model):
""" Definition d'un role (routeur principal, routeur de backkup)"""
""" Sert à la génération automatique de la conf des serveurs"""
PRETTY_NAME = "Roles des serveurs"
role_type = models.CharField(max_length=255, unique=True)
servers = models.ManyToManyField('Interface')
class Meta:
permissions = (
("view_role", "Peut voir un objet service"),
)
def save(self, *args, **kwargs):
super(Role, self).save(*args, **kwargs)
def __str__(self):
return str(self.role_type)
class Service(RevMixin, AclMixin, models.Model):
""" Definition d'un service (dhcp, dns, etc)"""
PRETTY_NAME = "Services à générer (dhcp, dns, etc)"
......
......@@ -118,6 +118,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</a>
</li>
{% acl_end %}
{% can_create SshFingerprint interface.machine.id %}
<li>
<a href="{% url 'machines:index-sshfingerprint' interface.machine.id %}">
<i class="fa fa-edit"></i> Gerer les fingerprint ssh
</a>
</li>
{% acl_end %}
{% can_create OuverturePortList %}
<li>
<a href="{% url 'machines:port-config' interface.id%}">
......
{% 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>Nom du role</th>
<th>Serveurs inclus</th>
<th></th>
<th></th>
</tr>
</thead>
{% for role in role_list %}
<tr>
<td>{{ role.role_type }}</td>
<td>{% for serv in role.servers.all %}{{ serv }}, {% endfor %}</td>
<td class="text-right">
{% can_edit role %}
{% include 'buttons/edit.html' with href='machines:edit-role' id=role.id %}
{% acl_end %}
{% include 'buttons/history.html' with href='machines:history' name='role' id=role.id %}
</td>
</tr>
{% endfor %}
</table>
{% 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 Gabriel Détraz
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 %}
<div class="table-responsive">
<table class="table table-striped long_text">
<thead>
<tr>
<th class="long_text">Entrée du hash</th>
<th>Algorithme utilisé</th>
<th>Commentaire</th>
<th></th>
</tr>
</thead>
{% for sshfpr in sshfingerprint_list %}
<tr>
<td class="long_text">{{ sshfpr.pub_key_entry }}</td>
<td>{{ sshfpr.algo }}</td>
<td>{{ sshfpr.comment }}</td>
<td class="text-right">
{% can_edit sshfpr %}
{% include 'buttons/edit.html' with href='machines:edit-sshfingerprint' id=sshfpr.id %}
{% acl_end %}
{% can_delete sshfpr %}
{% include 'buttons/suppr.html' with href='machines:del-sshfingerprint' id=sshfpr.id %}
{% acl_end %}
{% include 'buttons/history.html' with href='machines:history' name='sshfingerprint' id=sshfpr.id %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% 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 Gabriel Détraz
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>Nom de l'algo</th>
<th></th>
</tr>
</thead>
{% for sshfpralgo in sshfpralgo_list %}
<tr>
<td>{{ sshfpralgo.name }}</td>
<td class="text-right">
{% can_edit sshfpralgo %}
{% include 'buttons/edit.html' with href='machines:edit-sshfpralgo' id=sshfpralgo.id %}
{% acl_end %}
{% can_delete sshfpralgo %}
{% include 'buttons/suppr.html' with href='machines:del-sshfpralgo' id=sshfpralgo.id %}
{% acl_end %}
{% include 'buttons/history.html' with href='machines:history' name='sshfpralgo' id=sshfpralgo.id %}
</td>
</tr>
{% endfor %}
</table>
{% extends "machines/sidebar.html" %}
{% 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 bootstrap3 %}
{% load acl %}
{% block title %}Machines{% endblock %}
{% block content %}
<h2>Liste des roles</h2>
{% can_create Role %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:add-role' %}"><i class="fa fa-plus"></i> Ajouter un role</a>
{% acl_end %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'machines:del-role' %}"><i class="fa fa-trash"></i> Supprimer un ou plusieurs role</a>
{% include "machines/aff_role.html" with role_list=role_list %}
<br />
<br />
{% endblock %}
{% extends "machines/sidebar.html" %}
{% 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 Gabriel Détraz
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 bootstrap3 %}
{% load acl %}
{% block title %}Machines{% endblock %}
{% block content %}
<h2>Liste des fingerprint ssh</h2>
{% can_create SshFingerprint machine_id %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:new-sshfingerprint' machine_id %}"><i class="fa fa-plus"></i> Ajouter une fingerprint ssh</a>
{% acl_end %}
{% include "machines/aff_sshfingerprint.html" with sshfingerprint_list=sshfingerprint_list %}
<br />
<br />
<br />
{% endblock %}
{% extends "machines/sidebar.html" %}
{% 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 Gabriel Détraz
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 bootstrap3 %}
{% load acl %}
{% block title %}Machines{% endblock %}
{% block content %}
<h2>Liste des algo fingerprint ssh</h2>
{% can_create SshFprAlgo %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:new-sshfpralgo' %}"><i class="fa fa-plus"></i> Ajouter un algo ssh</a>
{% acl_end %}
{% include "machines/aff_sshfpralgo.html" with sshfpralgo_list=sshfpralgo_list %}
<br />
<br />
<br />
{% endblock %}
......@@ -66,6 +66,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if serviceform %}
{% bootstrap_form_errors serviceform %}
{% endif %}
{% if roleform %}
{% bootstrap_form_errors roleform %}
{% endif %}
{% if vlanform %}
{% bootstrap_form_errors vlanform %}
{% endif %}
......@@ -75,6 +78,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if ipv6form %}
{% bootstrap_form_errors ipv6form %}
{% endif %}
{% if sshfingerprintform %}
{% bootstrap_form_errors sshfingerprintform %}
{% endif %}
{% if sshfpralgoform %}
{% bootstrap_form_errors sshfpralgoform %}
{% endif %}
<form class="form" method="post">
{% csrf_token %}
......@@ -134,6 +146,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<h3>Service</h3>
{% massive_bootstrap_form serviceform 'servers' %}
{% endif %}
{% if roleform %}
<h3>Role</h3>
{% massive_bootstrap_form roleform 'servers' %}
{% endif %}
{% if vlanform %}
<h3>Vlan</h3>
{% bootstrap_form vlanform %}
......@@ -146,6 +162,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<h3>Ipv6</h3>
{% bootstrap_form ipv6form %}
{% endif %}
{% if sshfingerprintform %}
<h3>SshFingerprint</h3>
{% bootstrap_form sshfingerprintform %}
{% endif %}
{% if sshfpralgoform %}
<h3>Algorithme de fingerprint ssh</h3>
{% bootstrap_form sshfpralgoform %}
{% endif %}
{% bootstrap_button action_name button_type="submit" icon="star" %}
</form>
<br />
......
......@@ -44,6 +44,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Extensions et zones
</a>
{% acl_end %}
{% can_view_all SshFprAlgo %}
<a class="list-group-item list-group-item-info" href="{% url "machines:index-sshfpralgo" %}">
<i class="fa fa-list-ul"></i>
Algo de fingerprint ssh
</a>
{% acl_end %}
{% can_view_all IpType %}
<a class="list-group-item list-group-item-info" href="{% url "machines:index-iptype" %}">
<i class="fa fa-list-ul"></i>
......@@ -68,6 +74,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Services (dhcp, dns...)
</a>
{% acl_end %}
{% can_view_all Role %}
<a class="list-group-item list-group-item-info" href="{% url "machines:index-role" %}">
<i class="fa fa-list-ul"></i>
Roles des serveurs
</a>
{% acl_end %}
{% can_view_all OuverturePortList %}
<a class="list-group-item list-group-item-info" href="{% url "machines:index-portlist" %}">
<i class="fa fa-list-ul"></i>
......
......@@ -21,7 +21,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""machines.urls
The defined URLs for the Cotisations app
The defined URLs for the Machines app
"""
from __future__ import unicode_literals
......@@ -105,12 +105,42 @@ urlpatterns = [
url(r'^index_ipv6/(?P<interfaceid>[0-9]+)$',
views.index_ipv6,
name='index-ipv6'),
url(r'^new_sshfingerprint/(?P<machineid>[0-9]+)$',
views.new_sshfingerprint,
name='new-sshfingerprint'),
url(r'^edit_sshfingerprint/(?P<sshfingerprintid>[0-9]+)$',
views.edit_sshfingerprint,
name='edit-sshfingerprint'),
url(r'^del_sshfingerprint/(?P<sshfingerprintid>[0-9]+)$',
views.del_sshfingerprint,
name='del-sshfingerprint'),
url(r'^index_sshfingerprint/(?P<machineid>[0-9]+)$',
views.index_sshfingerprint,
name='index-sshfingerprint'),
url(r'^new_sshfpralgo/$',
views.new_sshfpralgo,
name='new-sshfpralgo'),
url(r'^edit_sshfpralgo/(?P<sshfpralgoid>[0-9]+)$',
views.edit_sshfpralgo,
name='edit-sshfpralgo'),
url(r'^del_sshfpralgo/(?P<sshfpralgoid>[0-9]+)$',
views.del_sshfpralgo,
name='del-sshfpralgo'),
url(r'^index_sshfpralgo/$',
views.index_sshfpralgo,
name='index-sshfpralgo'),
url(r'^add_service/$', views.add_service, name='add-service'),
url(r'^edit_service/(?P<serviceid>[0-9]+)$',
views.edit_service,
name='edit-service'),
url(r'^del_service/$', views.del_service, name='del-service'),
url(r'^index_service/$', views.index_service, name='index-service'),
url(r'^add_role/$', views.add_role, name='add-role'),
url(r'^edit_role/(?P<roleid>[0-9]+)$',
views.edit_role,
name='edit-role'),
url(r'^del_role/$', views.del_role, name='del-role'),
url(r'^index_role/$', views.index_role, name='index-role'),
url(r'^add_vlan/$', views.add_vlan, name='add-vlan'),
url(r'^edit_vlan/(?P<vlanid>[0-9]+)$', views.edit_vlan, name='edit-vlan'),
url(r'^del_vlan/$', views.del_vlan, name='del-vlan'),
......
......@@ -97,6 +97,8 @@ from .forms import (
DelMxForm,
VlanForm,
DelVlanForm,
RoleForm,
DelRoleForm,
ServiceForm,
DelServiceForm,
NasForm,
......@@ -105,7 +107,9 @@ from .forms import (
DelSrvForm,
Ipv6ListForm,
EditOuverturePortListForm,
EditOuverturePortConfigForm
EditOuverturePortConfigForm,
SshFingerprintForm,
SshFprAlgoForm,
)
from .models import (
IpType,
......@@ -117,6 +121,7 @@ from .models import (
Mx,
Ns,
Domain,
Role,
Service,
Service_link,
Vlan,
......@@ -126,6 +131,8 @@ from .models import (
OuverturePortList,
OuverturePort,
Ipv6List,
SshFingerprint,
SshFprAlgo,
)
......@@ -456,6 +463,138 @@ def del_ipv6list(request, ipv6list, **_kwargs):
)
@login_required
@can_create(SshFingerprint)
@can_edit(Machine)
def new_sshfingerprint(request, machine, **_kwargs):
"""Nouvelle sshfingerprint"""
sshfingerprint_instance = SshFingerprint(machine=machine)
sshfingerprint = SshFingerprintForm(
request.POST or None,
instance=sshfingerprint_instance
)
if sshfingerprint.is_valid():
sshfingerprint.save()
messages.success(request, "Fingerprint ssh ajoutée")
return redirect(reverse(
'machines:index-sshfingerprint',
kwargs={'machineid': str(machine.id)}
))
return form(
{'sshfingerprintform': sshfingerprint, 'action_name': 'Créer'},
'machines/machine.html',
request
)
@login_required
@can_edit(SshFingerprint)
def edit_sshfingerprint(request, sshfingerprint_instance, **_kwargs):
"""Edition d'une sshfingerprint"""
sshfingerprint = SshFingerprintForm(
request.POST or None,
instance=sshfingerprint_instance
)
if sshfingerprint.is_valid():
if sshfingerprint.changed_data:
sshfingerprint.save()
messages.success(request, "Ssh fingerprint modifiée")
return redirect(reverse(
'machines:index-sshfingerprint',
kwargs={'machineid': str(sshfingerprint_instance.machine.id)}
))
return form(
{'sshfingerprintform': sshfingerprint, 'action_name': 'Editer'},
'machines/machine.html',
request
)
@login_required
@can_delete(SshFingerprint)
def del_sshfingerprint(request, sshfingerprint, **_kwargs):
""" Supprime une sshfingerprint"""
if request.method == "POST":
machineid = sshfingerprint.machine.id
sshfingerprint.delete()
messages.success(request, "La sshfingerprint a été détruite")
return redirect(reverse(
'machines:index-sshfingerprint',
kwargs={'machineid': str(machineid)}
))
return form(
{'objet': sshfingerprint, 'objet_name': 'sshfingerprint'},
'machines/delete.html',
request
)
@login_required
@can_create(SshFprAlgo)
def new_sshfpralgo(request, **_kwargs):
"""Nouvelle sshfpralgo"""
sshfpralgo = SshFprAlgoForm(
request.POST or None,
)
if sshfpralgo.is_valid():
sshfpralgo.save()
messages.success(request, "Algo Fingerprint ssh ajouté")
return redirect(reverse(
'machines:index-sshfpralgo'
))
return form(
{'sshfpralgoform': sshfpralgo, 'action_name': 'Créer'},
'machines/machine.html',
request
)
@login_required
@can_edit(SshFprAlgo)
def edit_sshfpralgo(request, sshfpralgo_instance, **_kwargs):
"""Edition d'une sshfpralgo"""
sshfpralgo = SshFprAlgoForm(
request.POST or None,
instance=sshfpralgo_instance
)
if sshfpralgo.is_valid():
if sshfpralgo.changed_data:
sshfpralgo.save()
messages.success(request, "Algo de sshfp modifiée")
return redirect(reverse(
'machines:index-sshfpralgo'
))
return form(
{'sshfpralgoform': sshfpralgo, 'action_name': 'Editer'},
'machines/machine.html',
request
)
@login_required
@can_delete(SshFprAlgo)
def del_sshfpralgo(request, sshfpralgo, **_kwargs):
""" Supprime une sshfpralgo"""
if request.method == "POST":
try:
sshfpralgo.delete()
messages.success(request, "La sshfpralgo a été détruite")
except ProtectedError:
messages.error(
request,
("L'algo est affectée à au moins une fingerprint ssh, "
"vous ne pouvez pas le supprimer")
)
return redirect(reverse(
'machines:index-sshfpralgo'
))
return form(
{'objet': sshfpralgo, 'objet_name': 'sshfpralgo'},
'machines/delete.html',
request
)
@login_required
@can_create(IpType)
def add_iptype(request):
......@@ -1011,6 +1150,65 @@ def del_alias(request, interface, interfaceid):
)
@login_required
@can_create(Role)
def add_role(request):
""" View used to add a Role object """
role = RoleForm(request.POST or None)
if role.is_valid():
role.save()
messages.success(request, "Cet enregistrement role a été ajouté")
return redirect(reverse('machines:index-role'))
return form(
{'roleform': role, 'action_name': 'Créer'},
'machines/machine.html',
request
)
@login_required
@can_edit(Role)
def edit_role(request, role_instance, **_kwargs):
""" View used to edit a Role object """
role = RoleForm(request.POST or None, instance=role_instance)
if role.is_valid():
if role.changed_data:
role.save()
messages.success(request, "Role modifié")
return redirect(reverse('machines:index-role'))
return form(
{'roleform': role, 'action_name': 'Editer'},
'machines/machine.html',
request
)
@login_required
@can_delete_set(Role)
def del_role(request, instances):
""" View used to delete a Service object """
role = DelRoleForm(request.POST or None, instances=instances)
if role.is_valid():
role_dels = role.cleaned_data['role']
for role_del in role_dels:
try:
role_del.delete()
messages.success(request, "Le role a été supprimée")
except ProtectedError:
messages.error(
request,
("Erreur le role suivant %s ne peut être supprimé"
% role_del)
)
return redirect(reverse('machines:index-role'))
return form(
{'roleform': role, 'action_name': 'Supprimer'},
'machines/machine.html',
request
)
@login_required
@can_create(Service)
def add_service(request):
......@@ -1324,6 +1522,30 @@ def index_alias(request, interface, interfaceid):
)
@login_required
@can_edit(Machine)
def index_sshfingerprint(request, machine, machineid):
""" View used to display the list of existing IPv6 of an interface """
sshfingerprint_list = SshFingerprint.objects.filter(machine=machine)
return render(
request,
'machines/index_sshfingerprint.html',
{'sshfingerprint_list': sshfingerprint_list, 'machine_id': machineid}
)
@login_required
@can_view_all(SshFprAlgo)
def index_sshfpralgo(request):
""" View used to display the list of existing sshfrpalgo"""
sshfpralgo_list = SshFprAlgo.objects.all()
return render(
request,
'machines/index_sshfpralgo.html',
{'sshfpralgo_list': sshfpralgo_list}
)
@login_required
@can_edit(Interface)
def index_ipv6(request, interface, interfaceid):
......@@ -1336,6 +1558,21 @@ def index_ipv6(request, interface, interfaceid):
)
@login_required
@can_view_all(Role)
def index_role(request):
""" View used to display the list of existing roles """
role_list = (Role.objects
.prefetch_related(
'servers__domain__extension'
).all())
return render(
request,
'machines/index_role.html',
{'role_list': role_list}
)
@login_required
@can_view_all(Service)
def index_service(request):
......
......@@ -109,8 +109,11 @@ MODEL_NAME = {
'Ipv6List': machines.models.Ipv6List,
'machines.Service': machines.models.Service,
'Service_link': machines.models.Service_link,
'Role': machines.models.Role,
'OuverturePortList': machines.models.OuverturePortList,
'OuverturePort': machines.models.OuverturePort,
'SshFingerprint': machines.models.SshFingerprint,
'SshFprAlgo': machines.models.SshFprAlgo,
# preferences
'OptionalUser': preferences.models.OptionalUser,
'OptionalMachine': preferences.models.OptionalMachine,
......@@ -131,6 +134,8 @@ MODEL_NAME = {
'SwitchBay': topologie.models.SwitchBay,
# users
'User': users.models.User,
'Mail': users.models.Mail,
'MailAlias': users.models.MailAlias,
'Adherent': users.models.Adherent,
'Club': users.models.Club,
'ServiceUser': users.models.ServiceUser,
......
......@@ -125,9 +125,12 @@ HISTORY_BIND = {
'srv': machines.models.Srv,
'ns': machines.models.Ns,
'service': machines.models.Service,
'role': machines.models.Role,
'vlan': machines.models.Vlan,
'nas': machines.models.Nas,
'ipv6list': machines.models.Ipv6List,
'sshfingerprint': machines.models.SshFingerprint,
'sshfpralgo': machines.models.SshFprAlgo,
},
}
......
......@@ -96,3 +96,19 @@ footer a {
overflow-y: visible;
}
/* For tables with long text in cells */
.table.long_text{
table-layout: fixed;
width: 100%;
}
td.long_text{
word-wrap: break-word;
width: 40%;
}
th.long_text{
width: 60%;
}
......@@ -127,10 +127,6 @@ class AccessPoint(AclMixin, Machine):
switchbay__switch=self.switch()
)
@cached_property
def short_name(self):
return str(self.interface_set.first().domain.name)
@classmethod
def all_ap_in(cls, building_instance):
"""Get a building as argument, returns all ap of a building"""
......
......@@ -34,6 +34,8 @@ from reversion.admin import VersionAdmin
from .models import (
User,
Mail,
MailAlias,
ServiceUser,
School,
ListRight,
......
......@@ -53,6 +53,7 @@ from .models import (
School,
ListRight,
Whitelist,
MailAlias,
ListShell,
Ban,
Adherent,
......@@ -589,3 +590,16 @@ class WhitelistForm(FormRevMixin, ModelForm):
model = Whitelist
exclude = ['user']
widgets = {'date_end':DateTimePicker}
class MailAliasForm(FormRevMixin, ModelForm):
"""Creation, edition d'un objet alias mail"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(MailAliasForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['valeur'].label = 'nom de l\'adresse mail'
self.fields['extension'].label = 'extension de l\'adresse mail'
class Meta:
model = MailAlias
exclude = ['mail']
......@@ -79,7 +79,7 @@ from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin, RevMixin
from cotisations.models import Cotisation, Facture, Paiement, Vente
from machines.models import Domain, Interface, Machine, regen
from machines.models import Domain, Interface, Machine, regen, Extension
from preferences.models import GeneralOption, AssoOption, OptionalUser
from preferences.models import OptionalMachine, MailMessageOption
......@@ -195,6 +195,12 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
validators=[linux_user_validator]
)
email = models.EmailField()
"""
email= models.OneToOneField(
Mail,
on_delete=models.PROTECT
)
"""
school = models.ForeignKey(
'School',
on_delete=models.PROTECT,
......@@ -246,7 +252,9 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
("view_user",
"Peut voir un objet user quelquonque"),
)
@cached_property
def name(self):
"""Si il s'agit d'un adhérent, on renvoie le prénom"""
......@@ -668,6 +676,15 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser,
self.pwd_ntlm = hashNT(password)
return
def get_mail(self):
"""
Return the mail address choosen by the user
"""
if not self.mail.internal_activated:
return(self.mail.external)
else:
return(self.mail.mailalias_set.first())
def get_next_domain_name(self):
"""Look for an available name for a new interface for
this user by trying "pseudo0", "pseudo1", "pseudo2", ...
......@@ -1576,3 +1593,99 @@ class LdapServiceUserGroup(ldapdb.models.Model):
def __str__(self):
return self.name
class Mail(RevMixin, AclMixin, models.Model):
"""
Mail account of a user
Compte mail d'un utilisateur
"""
external_mail = models.EmailField(help_text="Mail externe")
user = models.ForeignKey(
'User',
on_delete=models.CASCADE,
help_text="Object mail d'un User"
)
redirection = models.BooleanField(
default=False
)
internal_address = models.BooleanField(
default=False
)
def __str__(self):
return self.mail
class MailAlias(RevMixin, AclMixin, models.Model):
"""
Define a alias for a user Mail
Définit un aliase pour un Mail d'utilisateur
"""
mail = models.ForeignKey(
'Mail',
on_delete=models.CASCADE,
help_text="Objects Mail associé"
)
valeur = models.CharField(
max_length=64,
help_text="username de l'adresse mail"
)
extension = models.ForeignKey(
'machines.Extension',
on_delete=models.CASCADE,
help_text="Extension mail interne"
)
class Meta:
unique_together = ('valeur', 'extension',)
def __str__(self):
return self.valeur + "@" + self.extension
def can_view(self, user_request, *_args, **_kwargs):
"""
Check if the user can view the aliases
"""
if user_request.has_perm('users.view_mailalias') or user.request == self.mail.user:
return True, None
else:
return False, "Vous n'avais pas les droits suffisants et n'êtes pas propriétaire de ces alias"
def can_delete(self, user_request, *_args, **_kwargs):
"""
Check if the user can delete the alias
"""
if user_request.has_perm('users.delete_mailalias'):
return True, None
else:
if user_request == self.mail.user:
if self.id != 0:
return True, None
else:
return False, "Vous ne pouvez pas supprimer l'alias lié à votre pseudo"
else:
return False, "Vous n'avez pas les droits suffisants et n'êtes pas propriétairs de ces alias"
def can_edit(self, user_request, *_args, **_kwargs):
"""
Check if the user can edit the alias
"""
if user_request.has_perm('users.change_mailalias'):
return True, None
else:
if user_request == self.mail.user:
if self.id != 0:
return True, None
else:
return False, "Vous ne pouvez pas modifier l'alias lié à votre pseudo"
else:
return False, "Vous n'avez pas les droits suffisants et n'êtes pas propriétairs de cet alias"
{% 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 %}
{% if alias_list.paginator %}
{% include "pagination.html" with list=alias_list %}
{% endif %}
<table class="table table-striped">
<thead>
<tr>
<th>Alias</th>
<th></th>
</tr>
</thead>
{% for alias in alias_list %}
<td>{{ alias }}</td>
<td class="text-right">
{% can_delete alias %}
{% include 'buttons/suppr.html' with href='users:del-alias' id=alias.id %}
{% acl_end %}
{% can_edit alias %}
{% include 'buttons/edit.html' with href='users:edit-alias' id=alias.id %}
{% acl_end %}
{% include 'buttons/history.html' with href='users:history' name='alias' id=alias.id %}
</td>
</tr>
{% endfor %}
</table>
{% if alias_list.paginator %}
{% include "pagination.html" with list=alias_list %}
{% endif %}
{% extends "users/sidebar.html" %}
{% 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 bootstrap3 %}
{% block title %}Utilisateurs{% endblock %}
{% block content %}
<h2>Alias</h2>
{% include "users/aff_alias.html" with alias_list=alias_list %}
<br />
<br />
<br />
{% endblock %}
......@@ -65,6 +65,9 @@ urlpatterns = [
url(r'^del_whitelist/(?P<whitelistid>[0-9]+)$',
views.del_whitelist,
name='del-whitelist'),
url(r'^add_mailalias/(?P<userid>[0-9]+)$', views.add_mailalias, name='add-mailalias'),
url(r'^edit_mailalias/(?P<mailaliasid>[0-9]+)$', views.edit_mailalias, name='edit-mailalias'),
url(r'^del-mailalias/(?P<mailaliasid>[0-9]+)$', views.del_mailalias, name='del-mailalias'),
url(r'^add_school/$', views.add_school, name='add-school'),
url(r'^edit_sch