Ce serveur Gitlab sera éteint le 30 juin 2020, pensez à migrer vos projets vers les serveurs gitlab-research.centralesupelec.fr et gitlab-student.centralesupelec.fr !

...
 
Commits (7)
# Re2o # Re2o
Gnu public license v2.0 GNU public license v2.0
## Avant propos ## Avant propos
Re2o est un logiciel d'administration développé initiallement au rezometz. Il Re2o est un logiciel d'administration développé initialement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en se veut agnostique au réseau considéré, de manière à être installable en
quelques clics. quelques clics.
...@@ -31,15 +31,15 @@ Pour cela : ...@@ -31,15 +31,15 @@ Pour cela :
## Fonctionnement général ## Fonctionnement général
Re2o est séparé entre les models, qui sont visible sur le schéma des Re2o est séparé entre les models, qui sont visibles sur le schéma des
dépendances. Il s'agit en réalité des tables sql, et les fields etant les dépendances. Il s'agit en réalité des tables sql, et les fields étant les
colonnes. colonnes.
Ceci dit il n'est jamais nécessaire de toucher directement au sql, django Ceci dit il n'est jamais nécessaire de toucher directement au sql, django
procédant automatiquement à tout cela. procédant automatiquement à tout cela.
On crée donc différents models (user, right pour les droits des users, On crée donc différents models (user, right pour les droits des users,
interfaces, IpList pour l'ensemble des adresses ip, etc) interfaces, IpList pour l'ensemble des adresses ip, etc)
Du coté des forms, il s'agit des formulaire d'édition des models. Il Du coté des forms, il s'agit des formulaires d'édition des models. Il
s'agit de ModelForms django, qui héritent des models très simplement, voir la s'agit de ModelForms django, qui héritent des models très simplement, voir la
documentation django models forms. documentation django models forms.
...@@ -56,12 +56,20 @@ d'accéder à ces vues, utilisé par re2o-tools. ...@@ -56,12 +56,20 @@ d'accéder à ces vues, utilisé par re2o-tools.
# Requète en base de donnée # Requète en base de donnée
Pour avoir un shell, il suffit de lancer '''python3 manage.py shell''' Pour avoir un shell, lancer :
Pour charger des objets, example avec User, faire : ```.bash
''' from users.models import User''' python3 manage.py shell
Pour charger les objets django, il suffit de faire User.objects.all() ```
Pour charger des objets (exemple avec User), faire :
```.python
from users.models import User
```
Pour charger les objets django, il suffit de faire `User.objects.all()`
pour tous les users par exemple. pour tous les users par exemple.
Il est ensuite aisé de faire des requètes, par exemple Il est ensuite aisé de faire des requêtes, par exemple
User.objects.filter(pseudo='test') `User.objects.filter(pseudo='test')`
Des exemples et la documentation complète sur les requètes django sont
Des exemples et la documentation complète sur les requêtes django sont
disponible sur le site officiel. disponible sur le site officiel.
...@@ -227,9 +227,10 @@ def post_auth(data): ...@@ -227,9 +227,10 @@ def post_auth(data):
# On récupère le numéro du port sur l'output de freeradius. # On récupère le numéro du port sur l'output de freeradius.
# La ligne suivante fonctionne pour cisco, HP et Juniper # La ligne suivante fonctionne pour cisco, HP et Juniper
port = port.split(".")[0].split('/')[-1][-2:] port = port.split(".")[0].split('/')[-1][-2:]
out = decide_vlan_and_register_switch(nas_machine, nas_type, port, mac) out = decide_vlan_switch(nas_machine, nas_type, port, mac)
sw_name, room, reason, vlan_id = out sw_name, room, reason, vlan_id, decision = out
if decision:
log_message = '(fil) %s -> %s [%s%s]' % ( log_message = '(fil) %s -> %s [%s%s]' % (
sw_name + u":" + port + u"/" + str(room), sw_name + u":" + port + u"/" + str(room),
mac, mac,
...@@ -248,6 +249,15 @@ def post_auth(data): ...@@ -248,6 +249,15 @@ def post_auth(data):
), ),
() ()
) )
else:
log_message = '(fil) %s -> %s [Reject:%s]' % (
sw_name + u":" + port + u"/" + str(room),
mac,
(reason and u': ' + reason).encode('utf-8')
)
logger.info(log_message)
return radiusd.RLM_MODULE_REJECT
else: else:
return radiusd.RLM_MODULE_OK return radiusd.RLM_MODULE_OK
...@@ -277,7 +287,6 @@ def find_nas_from_request(nas_id): ...@@ -277,7 +287,6 @@ def find_nas_from_request(nas_id):
.select_related('machine__switch__stack')) .select_related('machine__switch__stack'))
return nas.first() return nas.first()
def check_user_machine_and_register(nas_type, username, mac_address): def check_user_machine_and_register(nas_type, username, mac_address):
"""Verifie le username et la mac renseignee. L'enregistre si elle est """Verifie le username et la mac renseignee. L'enregistre si elle est
inconnue. inconnue.
...@@ -317,7 +326,7 @@ def check_user_machine_and_register(nas_type, username, mac_address): ...@@ -317,7 +326,7 @@ def check_user_machine_and_register(nas_type, username, mac_address):
return (False, u"Machine inconnue", '') return (False, u"Machine inconnue", '')
def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, 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 """Fonction de placement vlan pour un switch en radius filaire auth par
mac. mac.
...@@ -337,16 +346,13 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -337,16 +346,13 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
- user à jour : VLAN_OK - user à jour : VLAN_OK
- interface inconnue : - interface inconnue :
- register mac désactivé : VLAN_NOK - register mac désactivé : VLAN_NOK
- register mac activé : - register mac activé -> redirection vers webauth
- dans la chambre associé au port, pas d'user ou non à
jour : VLAN_NOK
- user à jour, autocapture de la mac et VLAN_OK
""" """
# Get port from switch and port number # Get port from switch and port number
extra_log = "" extra_log = ""
# Si le NAS est inconnu, on place sur le vlan defaut # Si le NAS est inconnu, on place sur le vlan defaut
if not nas_machine: if not nas_machine:
return ('?', u'Chambre inconnue', u'Nas inconnu', VLAN_OK) return ('?', u'Chambre inconnue', u'Nas inconnu', VLAN_OK, True)
sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine)))
...@@ -361,7 +367,7 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -361,7 +367,7 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
# Aucune information particulière ne permet de déterminer quelle # Aucune information particulière ne permet de déterminer quelle
# politique à appliquer sur ce port # politique à appliquer sur ce port
if not port: if not port:
return (sw_name, "Chambre inconnue", u'Port inconnu', VLAN_OK) return (sw_name, "Chambre inconnue", u'Port inconnu', VLAN_OK, True)
# On récupère le profil du port # On récupère le profil du port
port_profile = port.get_port_profile port_profile = port.get_port_profile
...@@ -376,20 +382,21 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -376,20 +382,21 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
# Si le port est désactivé, on rejette sur le vlan de déconnexion # Si le port est désactivé, on rejette sur le vlan de déconnexion
if not port.state: if not port.state:
return (sw_name, port.room, u'Port desactivé', VLAN_NOK) return (sw_name, port.room, u'Port desactivé', VLAN_NOK, True)
# Si radius est désactivé, on laisse passer # Si radius est désactivé, on laisse passer
if port_profile.radius_type == 'NO': if port_profile.radius_type == 'NO':
return (sw_name, return (sw_name,
"", "",
u"Pas d'authentification sur ce port" + extra_log, u"Pas d'authentification sur ce port" + extra_log,
DECISION_VLAN) 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 # 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 == '802.1X' and port_profile.radius_type == '802.1X':
room = port.room or "Chambre/local inconnu" room = port.room or "Chambre/local inconnu"
return (sw_name, room, u'Acceptation authentification 802.1X', DECISION_VLAN) 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 # 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 # Si le port est en mode strict, on vérifie que tous les users
...@@ -399,16 +406,16 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -399,16 +406,16 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
if port_profile.radius_mode == 'STRICT': if port_profile.radius_mode == 'STRICT':
room = port.room room = port.room
if not room: if not room:
return (sw_name, "Inconnue", u'Chambre inconnue', VLAN_NOK) return (sw_name, "Inconnue", u'Chambre inconnue', VLAN_NOK, True)
room_user = User.objects.filter( room_user = User.objects.filter(
Q(club__room=port.room) | Q(adherent__room=port.room) Q(club__room=port.room) | Q(adherent__room=port.room)
) )
if not room_user: if not room_user:
return (sw_name, room, u'Chambre non cotisante', VLAN_NOK) return (sw_name, room, u'Chambre non cotisante -> Web redirect', None, False)
for user in room_user: for user in room_user:
if not user.has_access(): if not user.has_access():
return (sw_name, room, u'Chambre resident desactive', VLAN_NOK) return (sw_name, room, u'Chambre resident desactive -> Web redirect', None, False)
# else: user OK, on passe à la verif MAC # 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
...@@ -424,64 +431,11 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -424,64 +431,11 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
# On essaye de register la mac, si l'autocapture a été activée # On essaye de register la mac, si l'autocapture a été activée
# Sinon on rejette sur vlan_nok # Sinon on rejette sur vlan_nok
if not nas_type.autocapture_mac: if not nas_type.autocapture_mac:
return (sw_name, "", u'Machine inconnue', VLAN_NOK) return (sw_name, "", u'Machine inconnue', VLAN_NOK, True)
# On ne peut autocapturer que si on connait la chambre et donc l'user correspondant # On rejette pour basculer sur du webauth
elif not room:
return (sw_name,
"Inconnue",
u'Chambre et machine inconnues',
VLAN_NOK)
else: else:
# Si la chambre est vide (local club, prises en libre services) return (sw_name, room, u'Machine Inconnue -> Web redirect', None, False)
# Impossible d'autocapturer
if not room_user:
room_user = User.objects.filter(
Q(club__room=port.room) | Q(adherent__room=port.room)
)
if not room_user:
return (sw_name,
room,
u'Machine et propriétaire de la chambre '
'inconnus',
VLAN_NOK)
# Si il y a plus d'un user dans la chambre, impossible de savoir à qui
# Ajouter la machine
elif room_user.count() > 1:
return (sw_name,
room,
u'Machine inconnue, il y a au moins 2 users '
'dans la chambre/local -> ajout de mac '
'automatique impossible',
VLAN_NOK)
# Si l'adhérent de la chambre n'est pas à jour de cotis, pas d'autocapture
elif not room_user.first().has_access():
return (sw_name,
room,
u'Machine inconnue et adhérent non cotisant',
VLAN_NOK)
# Sinon on capture et on laisse passer sur le bon vlan
else:
interface, reason = (room_user
.first()
.autoregister_machine(
mac_address,
nas_type
))
if interface:
## Si on choisi de placer les machines sur le vlan correspondant à leur type :
if RADIUS_POLICY == 'MACHINE':
DECISION_VLAN = interface.type.ip_type.vlan.vlan_id
return (sw_name,
room,
u'Access Ok, Capture de la mac: ' + extra_log,
DECISION_VLAN)
else:
return (sw_name,
room,
u'Erreur dans le register mac %s' % (
reason + str(mac_address)
),
VLAN_NOK)
# 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 # Si elle n'a pas d'ipv4, on lui en met une
# Enfin on laisse passer sur le vlan pertinent # Enfin on laisse passer sur le vlan pertinent
...@@ -491,7 +445,8 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -491,7 +445,8 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
return (sw_name, return (sw_name,
room, room,
u'Machine non active / adherent non cotisant', u'Machine non active / adherent non cotisant',
VLAN_NOK) VLAN_NOK,
True)
## Si on choisi de placer les machines sur le vlan correspondant à leur type : ## Si on choisi de placer les machines sur le vlan correspondant à leur type :
if RADIUS_POLICY == 'MACHINE': if RADIUS_POLICY == 'MACHINE':
DECISION_VLAN = interface.type.ip_type.vlan.vlan_id DECISION_VLAN = interface.type.ip_type.vlan.vlan_id
...@@ -500,9 +455,11 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number, ...@@ -500,9 +455,11 @@ def decide_vlan_and_register_switch(nas_machine, nas_type, port_number,
return (sw_name, return (sw_name,
room, room,
u"Ok, Reassignation de l'ipv4" + extra_log, u"Ok, Reassignation de l'ipv4" + extra_log,
DECISION_VLAN) DECISION_VLAN,
True)
else: else:
return (sw_name, return (sw_name,
room, room,
u'Machine OK' + extra_log, u'Machine OK' + extra_log,
DECISION_VLAN) DECISION_VLAN,
True)
...@@ -232,7 +232,7 @@ msgstr "Accéder à mon profil" ...@@ -232,7 +232,7 @@ msgstr "Accéder à mon profil"
#: templates/re2o/index.html:79 #: templates/re2o/index.html:79
msgid "Services of the organisation" msgid "Services of the organisation"
msgstr "Serices de l'association" msgstr "Services de l'association"
#: templates/re2o/index.html:93 #: templates/re2o/index.html:93
msgid "Go there" msgid "Go there"
......
...@@ -41,6 +41,8 @@ from django.utils import timezone ...@@ -41,6 +41,8 @@ from django.utils import timezone
from django.contrib.auth.models import Group, Permission from django.contrib.auth.models import Group, Permission
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from machines.models import Interface, Machine, Nas
from topologie.models import Port
from preferences.models import OptionalUser from preferences.models import OptionalUser
from re2o.utils import remove_user_room, get_input_formats_help_text from re2o.utils import remove_user_room, get_input_formats_help_text
from re2o.mixins import FormRevMixin from re2o.mixins import FormRevMixin
...@@ -660,3 +662,53 @@ class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm): ...@@ -660,3 +662,53 @@ class EmailSettingsForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
model = User model = User
fields = ['email','local_email_enabled', 'local_email_redirect'] fields = ['email','local_email_enabled', 'local_email_redirect']
class InitialRegisterForm(forms.Form):
register_room = forms.BooleanField(required=False)
register_machine = forms.BooleanField(required=False)
def __init__(self, *args, **kwargs):
switch_ip = kwargs.pop('switch_ip')
switch_port = kwargs.pop('switch_port')
client_mac = kwargs.pop('client_mac')
self.user = kwargs.pop('user')
if switch_ip and switch_port:
# Looking for a port
port = Port.objects.filter(switch__interface__ipv4__ipv4=switch_ip, port=switch_port).first()
# If a port exists, checking there is a room AND radius
if port:
if port.get_port_profile.radius_type != 'NO' and port.get_port_profile.radius_mode == 'STRICT' and hasattr(port, 'room'):
# Requesting user is not in this room ?
if self.user.room != port.room:
self.new_room = port.room
if client_mac and switch_ip:
# If this interface doesn't already exists
if not Interface.objects.filter(mac_address=client_mac):
self.mac_address = client_mac
self.nas_type = Nas.objects.filter(nas_type__interface__ipv4__ipv4=switch_ip).first()
super(InitialRegisterForm, self).__init__(*args, **kwargs)
if hasattr(self, 'new_room'):
self.fields['register_room'].label = _("New connection from room %s. Is it yours? If that is the case, type OK." % self.new_room)
else:
self.fields.pop('register_room')
if hasattr(self, 'mac_address'):
self.fields['register_machine'].label = _("New connection from new device. Register it? Say Yes to get Internet access from it (MAC Address : %s)." % self.mac_address)
else:
self.fields.pop('register_machine')
def clean_register_room(self):
if self.cleaned_data['register_room']:
if self.user.is_class_adherent:
remove_user_room(self.new_room)
user = self.user.adherent
user.room = self.new_room
user.save()
if self.user.is_class_club:
user = self.user.club
user.room = self.new_room
user.save()
def clean_register_machine(self):
if self.cleaned_data['register_machine']:
if self.mac_address and self.nas_type:
self.user.autoregister_machine(self.mac_address, self.nas_type)
This diff is collapsed.
{% 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 %}
{% load massive_bootstrap_form %}
{% load static %}
{% load i18n %}
{% block title %}{% trans "Users" %}{% endblock %}
{% block content %}
<h3>{% trans "Your machine and your room were successfully registered. Please disconnect and reconnect your Ethernet cable to benefit from a wired connection." %}</h3>
<center><img src="{% static '/images/rj45.gif' %}" alt="rj45_in_out"></center>
<br/>
<br/>
<br/>
{% endblock %}
...@@ -109,6 +109,7 @@ urlpatterns = [ ...@@ -109,6 +109,7 @@ urlpatterns = [
url(r'^mass_archive/$', views.mass_archive, name='mass-archive'), url(r'^mass_archive/$', views.mass_archive, name='mass-archive'),
url(r'^$', views.index, name='index'), url(r'^$', views.index, name='index'),
url(r'^index_clubs/$', views.index_clubs, name='index-clubs'), url(r'^index_clubs/$', views.index_clubs, name='index-clubs'),
url(r'^initial_register/$', views.initial_register, name='initial-register'),
url(r'^rest/ml/std/$', url(r'^rest/ml/std/$',
views.ml_std_list, views.ml_std_list,
name='ml-std-list'), name='ml-std-list'),
......
...@@ -105,7 +105,8 @@ from .forms import ( ...@@ -105,7 +105,8 @@ from .forms import (
PassForm, PassForm,
ResetPasswordForm, ResetPasswordForm,
ClubAdminandMembersForm, ClubAdminandMembersForm,
GroupForm GroupForm,
InitialRegisterForm
) )
...@@ -1081,6 +1082,30 @@ def process_passwd(request, req): ...@@ -1081,6 +1082,30 @@ def process_passwd(request, req):
request request
) )
@login_required
def initial_register(request):
u_form = InitialRegisterForm(request.POST or None, user=request.user, switch_ip=request.GET.get('switch_ip', None), switch_port=request.GET.get('switch_port', None), client_mac=request.GET.get('client_mac', None))
if not u_form.fields:
messages.error(request, _("Incorrect URL, or already registered device"))
return redirect(reverse(
'users:profil',
kwargs={'userid': str(request.user.id)}
))
if u_form.is_valid():
messages.success(request, _("Successful registration! Please"
" disconnect and reconnect your Ethernet"
" cable to get Internet access."))
return form(
{},
'users/plugin_out.html',
request
)
return form(
{'userform': u_form, 'action_name': _("Register device or room")},
'users/user.html',
request
)
class JSONResponse(HttpResponse): class JSONResponse(HttpResponse):
""" Framework Rest """ """ Framework Rest """
......