Commit dc38c32a authored by LEVY-FALK Hugo's avatar LEVY-FALK Hugo Committed by root

ACL dans un fichier dédié dans chaque application.

parent 8fbcecd3
...@@ -21,3 +21,4 @@ ...@@ -21,3 +21,4 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from .acl import *
# 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.
""".acl
Here are defined some functions to check acl on the application.
"""
def can_view(user):
"""Check if an user can view the application.
Args:
user: The user who wants to view the application.
Returns:
A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None).
"""
can = user.has_perms(('cableur',))
return can, None if can else "Vous ne pouvez pas voir cette application."
...@@ -43,8 +43,8 @@ from users.models import User ...@@ -43,8 +43,8 @@ from users.models import User
from re2o.settings import LOGO_PATH from re2o.settings import LOGO_PATH
from re2o import settings from re2o import settings
from re2o.views import form from re2o.views import form
from re2o.utils import ( from re2o.utils import SortTable
SortTable, from re2o.acl import (
can_create, can_create,
can_edit, can_edit,
can_delete, can_delete,
......
...@@ -21,3 +21,4 @@ ...@@ -21,3 +21,4 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from .acl import *
# 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.
"""logs.acl
Here are defined some functions to check acl on the application.
"""
def can_view(user):
"""Check if an user can view the application.
Args:
user: The user who wants to view the application.
Returns:
A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None).
"""
can = user.has_perms(('cableur',))
return can, None if can else "Vous ne pouvez pas voir cette application."
...@@ -98,6 +98,8 @@ from re2o.utils import ( ...@@ -98,6 +98,8 @@ from re2o.utils import (
all_baned, all_baned,
all_has_access, all_has_access,
all_adherent, all_adherent,
)
from re2o.acl import (
can_view_all, can_view_all,
can_view_app, can_view_app,
can_edit_history, can_edit_history,
......
...@@ -21,3 +21,4 @@ ...@@ -21,3 +21,4 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from .acl import *
# 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.
"""machines.acl
Here are defined some functions to check acl on the application.
"""
def can_view(user):
"""Check if an user can view the application.
Args:
user: The user who wants to view the application.
Returns:
A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None).
"""
can = user.has_perms(('cableur',))
return can, None if can else "Vous ne pouvez pas voir cette application."
...@@ -124,6 +124,8 @@ from re2o.utils import ( ...@@ -124,6 +124,8 @@ from re2o.utils import (
all_has_access, all_has_access,
filter_active_interfaces, filter_active_interfaces,
SortTable, SortTable,
)
from re2o.acl import (
can_create, can_create,
can_edit, can_edit,
can_delete, can_delete,
...@@ -219,7 +221,7 @@ def generate_ipv4_mbf_param( form, is_type_tt ): ...@@ -219,7 +221,7 @@ def generate_ipv4_mbf_param( form, is_type_tt ):
@can_create(Machine) @can_create(Machine)
@can_edit(User) @can_edit(User)
def new_machine(request, user, userid): def new_machine(request, user, userid):
""" Fonction de creation d'une machine. Cree l'objet machine, """ Fonction de creation d'une machine. Cree l'objet machine,
le sous objet interface et l'objet domain à partir de model forms. le sous objet interface et l'objet domain à partir de model forms.
Trop complexe, devrait être simplifié""" Trop complexe, devrait être simplifié"""
...@@ -568,7 +570,7 @@ def add_mx(request): ...@@ -568,7 +570,7 @@ def add_mx(request):
@login_required @login_required
@can_edit(Mx) @can_edit(Mx)
def edit_mx(request, mx_instance, mxid): def edit_mx(request, mx_instance, mxid):
mx = MxForm(request.POST or None, instance=mx_instance) mx = MxForm(request.POST or None, instance=mx_instance)
if mx.is_valid(): if mx.is_valid():
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
...@@ -746,7 +748,7 @@ def add_alias(request, interface, interfaceid): ...@@ -746,7 +748,7 @@ def add_alias(request, interface, interfaceid):
reversion.set_comment("Création") reversion.set_comment("Création")
messages.success(request, "Cet alias a été ajouté") messages.success(request, "Cet alias a été ajouté")
return redirect(reverse( return redirect(reverse(
'machines:index-alias', 'machines:index-alias',
kwargs={'interfaceid':str(interfaceid)} kwargs={'interfaceid':str(interfaceid)}
)) ))
return form({'aliasform': alias}, 'machines/machine.html', request) return form({'aliasform': alias}, 'machines/machine.html', request)
...@@ -763,7 +765,7 @@ def edit_alias(request, domain_instance, domainid): ...@@ -763,7 +765,7 @@ def edit_alias(request, domain_instance, domainid):
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in alias.changed_data)) reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in alias.changed_data))
messages.success(request, "Alias modifié") messages.success(request, "Alias modifié")
return redirect(reverse( return redirect(reverse(
'machines:index-alias', 'machines:index-alias',
kwargs={'interfaceid':str(domain_instance.cname.interface_parent.id)} kwargs={'interfaceid':str(domain_instance.cname.interface_parent.id)}
)) ))
return form({'aliasform': alias}, 'machines/machine.html', request) return form({'aliasform': alias}, 'machines/machine.html', request)
...@@ -783,7 +785,7 @@ def del_alias(request, interface, interfaceid): ...@@ -783,7 +785,7 @@ def del_alias(request, interface, interfaceid):
except ProtectedError: except ProtectedError:
messages.error(request, "Erreur l'alias suivant %s ne peut être supprimé" % alias_del) messages.error(request, "Erreur l'alias suivant %s ne peut être supprimé" % alias_del)
return redirect(reverse( return redirect(reverse(
'machines:index-alias', 'machines:index-alias',
kwargs={'interfaceid':str(interfaceid)} kwargs={'interfaceid':str(interfaceid)}
)) ))
return form({'aliasform': alias}, 'machines/machine.html', request) return form({'aliasform': alias}, 'machines/machine.html', request)
......
# 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.
"""preferences.acl
Here are defined some functions to check acl on the application.
"""
def can_view(user):
"""Check if an user can view the application.
Args:
user: The user who wants to view the application.
Returns:
A couple (allowed, msg) where allowed is a boolean which is True if
viewing is granted and msg is a message (can be None).
"""
can = user.has_perms(('cableur',))
return can, None if can else "Vous ne pouvez pas voir cette application."
...@@ -42,7 +42,7 @@ from reversion.models import Version ...@@ -42,7 +42,7 @@ from reversion.models import Version
from reversion import revisions as reversion from reversion import revisions as reversion
from re2o.views import form from re2o.views import form
from re2o.utils 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
from .forms import ServiceForm, DelServiceForm from .forms import ServiceForm, DelServiceForm
from .models import Service, OptionalUser, OptionalMachine, AssoOption from .models import Service, OptionalUser, OptionalMachine, AssoOption
from .models import MailMessageOption, GeneralOption, OptionalTopologie from .models import MailMessageOption, GeneralOption, OptionalTopologie
......
# -*- mode: python; coding: utf-8 -*-
# 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.
"""Handles ACL for re2o.
Here are defined some decorators that can be used in views to handle ACL.
"""
from __future__ import unicode_literals
import sys
from django.contrib import messages
from django.shortcuts import redirect
from django.urls import reverse
import cotisations, logs, machines, preferences, search, topologie, users
def can_create(model):
"""Decorator to check if an user can create a model.
It assumes that a valid user exists in the request and that the model has a
method can_create(user) which returns true if the user can create this kind
of models.
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
can, msg = model.can_create(request.user, *args, **kwargs)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, *args, **kwargs)
return wrapper
return decorator
def can_edit(model, *field_list):
"""Decorator to check if an user can edit a model.
It tries to get an instance of the model, using
`model.get_instance(*args, **kwargs)` and assumes that the model has a
method `can_edit(user)` which returns `true` if the user can edit this
kind of models.
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
try:
instance = model.get_instance(*args, **kwargs)
except model.DoesNotExist:
messages.error(request, u"Entrée inexistante")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
can, msg = instance.can_edit(request.user)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
for field in field_list:
can_create = getattr(model, 'can_change_' + field)
can, msg = can_create(instance, request.user, *args, **kwargs)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, instance, *args, **kwargs)
return wrapper
return decorator
def can_change(model, *field_list):
"""Decorator to check if an user can edit a field of a model class.
Difference with can_edit : take a class and not an instance
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
for field in field_list:
can_create = getattr(model, 'can_change_' + field)
can, msg = can_create(request.user, *args, **kwargs)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, *args, **kwargs)
return wrapper
return decorator
def can_delete(model):
"""Decorator to check if an user can delete a model.
It tries to get an instance of the model, using
`model.get_instance(*args, **kwargs)` and assumes that the model has a
method `can_delete(user)` which returns `true` if the user can delete this
kind of models.
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
try:
instance = model.get_instance(*args, **kwargs)
except model.DoesNotExist:
messages.error(request, u"Entrée inexistante")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
can, msg = instance.can_delete(request.user)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, instance, *args, **kwargs)
return wrapper
return decorator
def can_delete_set(model):
"""Decorator which returns a list of detable models by request user.
If none of them, return an error"""
def decorator(view):
def wrapper(request, *args, **kwargs):
all_objects = model.objects.all()
instances_id = []
for instance in all_objects:
can, msg = instance.can_delete(request.user)
if can:
instances_id.append(instance.id)
instances = model.objects.filter(id__in=instances_id)
if not instances:
messages.error(request, "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, instances, *args, **kwargs)
return wrapper
return decorator
def can_view(model):
"""Decorator to check if an user can view a model.
It tries to get an instance of the model, using
`model.get_instance(*args, **kwargs)` and assumes that the model has a
method `can_view(user)` which returns `true` if the user can view this
kind of models.
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
try:
instance = model.get_instance(*args, **kwargs)
except model.DoesNotExist:
messages.error(request, u"Entrée inexistante")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
can, msg = instance.can_view(request.user)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, instance, *args, **kwargs)
return wrapper
return decorator
def can_view_all(model):
"""Decorator to check if an user can view a class of model.
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
can, msg = model.can_view_all(request.user)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return view(request, *args, **kwargs)
return wrapper
return decorator
def can_view_app(app_name):
"""Decorator to check if an user can view an application.
"""
assert app_name in sys.modules.keys()
def decorator(view):
def wrapper(request, *args, **kwargs):
app = sys.modules[app_name]
can,msg = app.can_view(request.user)
if can:
return view(request, *args, **kwargs)
messages.error(request, msg)
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return wrapper
return decorator
def can_edit_history(view):
"""Decorator to check if an user can edit history."""
def wrapper(request, *args, **kwargs):
if request.user.has_perms(('admin',)):
return view(request, *args, **kwargs)
messages.error(
request,
"Vous ne pouvez pas éditer l'historique."
)
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
))
return wrapper
...@@ -2,19 +2,19 @@ ...@@ -2,19 +2,19 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # 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 # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2017 Maël Kervella # Copyright © 2017 Maël Kervella
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License along # 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., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
......
...@@ -48,7 +48,7 @@ an instance of a model (either Model.can_xxx or instance.can_xxx) ...@@ -48,7 +48,7 @@ an instance of a model (either Model.can_xxx or instance.can_xxx)
**Example**: **Example**:
{% can_create Machine targeted_user %} {% can_create Machine targeted_user %}
<p>I'm authorized to create new machines for this guy \\o/</p> <p>I'm authorized to create new machines.models.for this guy \\o/</p>
{% acl_else %} {% acl_else %}
<p>Why can't I create a little machine for this guy ? :(</p> <p>Why can't I create a little machine for this guy ? :(</p>
{% acl_end %} {% acl_end %}
...@@ -70,72 +70,71 @@ an instance of a model (either Model.can_xxx or instance.can_xxx) ...@@ -70,72 +70,71 @@ an instance of a model (either Model.can_xxx or instance.can_xxx)
the acl function exists in the model definition the acl function exists in the model definition
""" """
import sys
from django import template from django import template
from django.template.base import Node, NodeList from django.template.base import Node, NodeList
from re2o.utils import APP_VIEWING_RIGHT import cotisations
import machines
import cotisations.models as cotisations import preferences
import machines.models as machines import topologie
import preferences.models as preferences import users
import topologie.models as topologie
import users.models as users
register = template.Library() register = template.Library()
MODEL_NAME = { MODEL_NAME = {
# cotisations # cotisations
'Facture' : cotisations.Facture, 'Facture' : cotisations.models.Facture,
'Vente' : cotisations.Vente, 'Vente' : cotisations.models.Vente,
'Article' : cotisations.Article, 'Article' : cotisations.models.Article,
'Banque' : cotisations.Banque, 'Banque' : cotisations.models.Banque,
'Paiement' : cotisations.Paiement, 'Paiement' : cotisations.models.Paiement,
'Cotisation' : cotisations.Cotisation, 'Cotisation' : cotisations.models.Cotisation,
# machines # machines
'Machine' : machines.Machine, 'Machine' : machines.models.Machine,
'MachineType' : machines.MachineType, 'MachineType' : machines.models.MachineType,
'IpType' : machines.IpType, 'IpType' : machines.models.IpType,
'Vlan' : machines.Vlan, 'Vlan' : machines.models.Vlan,
'Nas' : machines.Nas, 'Nas' : machines.models<