From c213703a30cf3c75bdfaa149ca0f22d82a5ca534 Mon Sep 17 00:00:00 2001 From: chapeau Date: Sat, 28 Nov 2020 12:09:36 +0100 Subject: [PATCH] premiere version de l'api radius --- radius/__init__.py | 0 radius/api/__init__.py | 0 radius/api/serializers.py | 98 ++++++++++++++++++++++++++++ radius/api/urls.py | 35 ++++++++++ radius/api/views.py | 133 ++++++++++++++++++++++++++++++++++++++ radius/urls.py | 4 ++ radius/views.py | 0 7 files changed, 270 insertions(+) create mode 100644 radius/__init__.py create mode 100644 radius/api/__init__.py create mode 100644 radius/api/serializers.py create mode 100644 radius/api/urls.py create mode 100644 radius/api/views.py create mode 100644 radius/urls.py create mode 100644 radius/views.py diff --git a/radius/__init__.py b/radius/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/radius/api/__init__.py b/radius/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/radius/api/serializers.py b/radius/api/serializers.py new file mode 100644 index 00000000..41959eb9 --- /dev/null +++ b/radius/api/serializers.py @@ -0,0 +1,98 @@ +from rest_framework import serializers + +import machines.models as machines +import users.models as users +from api.serializers import NamespacedHMSerializer +from rest_framework.serializers import Serializer + + +class InterfaceSerializer(Serializer): + mac_address = serializers.CharField() + ipv4 = serializers.CharField(source="ipv4.ipv4") + active = serializers.BooleanField(source="is_active") + user_pk = serializers.CharField(source="machine.user.pk") + # machine_type_pk = serializers.CharField(source="machine_type.pk") + # switch_stack = serializers.CharField(source="machine.switch.stack") + machine_short_name = serializers.CharField(source="machine.short_name") + is_ban = serializers.BooleanField(source="machine.user.is_ban") + vlan_id = serializers.IntegerField( + source="machine_type.ip_type.vlan.vlan_id") + + +class NasSerializer(Serializer): + port_access_mode = serializers.CharField() + autocapture_mac = serializers.BooleanField() + + +class UserSerializer(Serializer): + access = serializers.BooleanField(source="has_access") + pk = serializers.CharField() + pwd_ntlm = serializers.CharField() + state = serializers.CharField() + email_state = serializers.IntegerField() + is_ban = serializers.BooleanField() + is_connected = serializers.BooleanField() + is_whitelisted = serializers.BooleanField() + + +class PortSerializer(Serializer): + state = serializers.BooleanField() + room = serializers.CharField() + + +class VlanSerializer(Serializer): + vlan_id = serializers.IntegerField() + + +class PortProfileSerializer(Serializer): + vlan_untagged = VlanSerializer() + radius_type = serializers.CharField() + + +class SwitchSerializer(Serializer): + name = serializers.CharField(source="short_name") + ipv4 = serializers.CharField() + + +class RadiusAttributeSerializer(Serializer): + attribute = serializers.CharField() + value = serializers.CharField() + + +class RadiusOptionSerializer(Serializer): + radius_general_policy = serializers.CharField() + unknown_machine = serializers.CharField() + unknown_machine_vlan = VlanSerializer() + unknown_machine_attributes = RadiusAttributeSerializer(many=True) + unknown_port = serializers.CharField() + unknown_port_vlan = VlanSerializer() + unknown_port_attributes = RadiusAttributeSerializer(many=True) + unknown_room = serializers.CharField() + unknown_room_vlan = VlanSerializer() + unknown_room_attributes = RadiusAttributeSerializer(many=True) + non_member = serializers.CharField() + non_member_vlan = VlanSerializer() + non_member_attributes = RadiusAttributeSerializer(many=True) + banned = serializers.CharField() + banned_vlan = VlanSerializer() + banned_attributes = RadiusAttributeSerializer(many=True) + vlan_decision_ok = VlanSerializer() + ok_attributes = RadiusAttributeSerializer(many=True) + + +class AuthorizeResponseSerializer(Serializer): + nas = NasSerializer(read_only=True) + user = UserSerializer(read_only=True) + user_interface = InterfaceSerializer(read_only=True) + + +class PostAuthResponseSerializer(Serializer): + nas = NasSerializer(read_only=True) + room_users = UserSerializer(many=True) + port = PortSerializer() + port_profile = PortProfileSerializer(partial=True) + switch = SwitchSerializer() + user_interface = InterfaceSerializer() + radius_option = RadiusOptionSerializer() + EMAIL_STATE_UNVERIFIED = serializers.IntegerField() + RADIUS_OPTION_REJECT = serializers.CharField() diff --git a/radius/api/urls.py b/radius/api/urls.py new file mode 100644 index 00000000..af532a5b --- /dev/null +++ b/radius/api/urls.py @@ -0,0 +1,35 @@ +# -*- 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 © 2020 Corentin Canebier +# +# 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. + +from . import views + +urls_view = [ + # (r"radius/nas-interface-from-id/(?P.+)$", views.nas_from_id_view), + # (r"radius/nas-from-machine-type/(?P.+)$", views.NasFromMachineTypeView), + # (r"radius/user-from-username/(?P.+)$", views.UserFromUsernameView), + # (r"radius/interface-from-mac-address/(?P.+)$", views.InterfaceFromMacAddressView), +] +urls_functional_view = [ + (r"radius/authorize/(?P[^/]+)/(?P.+)/(?P[0-9a-fA-F:\-]{17})$", + views.authorize, None), + (r"radius/post_auth/(?P[^/]+)/(?P.+)/(?P[0-9a-fA-F:\-]{17})$", + views.post_auth, None), +] diff --git a/radius/api/views.py b/radius/api/views.py new file mode 100644 index 00000000..7c16f916 --- /dev/null +++ b/radius/api/views.py @@ -0,0 +1,133 @@ +# -*- 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 © 2020 Corentin Canebier +# +# 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. + +from rest_framework.decorators import api_view +from rest_framework.response import Response +from django.db.models import Q + +from . import serializers +from machines.models import Domain, IpList, Interface, Nas +from users.models import User +from preferences.models import RadiusOption +from topologie.models import Port, Switch + + +class AuthorizeResponse: + def __init__(self, nas, user, user_interface): + self.nas = nas + self.user = user + self.user_interface = user_interface + + def can_view(self, user): + return [True] + + +@api_view(['GET']) +def authorize(request, nas_id, username, mac_address): + + nas_interface = Interface.objects.filter( + Q(domain=Domain.objects.filter(name=nas_id)) + | Q(ipv4=IpList.objects.filter(ipv4=nas_id)) + ).first() + nas_type = None + if nas_interface: + nas_type = Nas.objects.filter( + nas_type=nas_interface.machine_type).first() + + user = User.objects.filter(pseudo__iexact=username).first() + user_interface = Interface.objects.filter(mac_address=mac_address).first() + + serialized = serializers.AuthorizeResponseSerializer( + AuthorizeResponse(nas_type, user, user_interface)) + + return Response(data=serialized.data) + + +class PostAuthResponse: + def __init__(self, nas, room_users, port, port_profile, switch, user_interface, radius_option, EMAIL_STATE_UNVERIFIED, RADIUS_OPTION_REJECT): + self.nas = nas + self.room_users = room_users + self.port = port + self.port_profile = port_profile + self.switch = switch + self.user_interface = user_interface + self.radius_option = radius_option + self.EMAIL_STATE_UNVERIFIED = EMAIL_STATE_UNVERIFIED + self.RADIUS_OPTION_REJECT = RADIUS_OPTION_REJECT + + def can_view(self, user): + return [True] + + +@api_view(['GET']) +def post_auth(request, nas_id, nas_port, user_mac): + # get nas_type + nas_interface = Interface.objects.prefetch_related("machine__switch__stack").filter( + Q(domain=Domain.objects.filter(name=nas_id)) + | Q(ipv4=IpList.objects.filter(ipv4=nas_id)) + ).first() + print(nas_id) + nas_type = None + if nas_interface: + nas_type = Nas.objects.filter( + nas_type=nas_interface.machine_type).first() + + # get switch + switch = Switch.objects.filter(machine_ptr=nas_interface.machine).first() + if hasattr(nas_interface.machine, "switch"): + stack = nas_interface.machine.switch.stack + if stack: + id_stack_member = nas_port.split("-")[1].split("/")[0] + switch = ( + Switch.objects.filter(stack=stack) + .filter(stack_member_id=id_stack_member) + .first() + ) + + # get port + port_number = nas_port.split(".")[0].split("/")[-1][-2:] + port = Port.objects.filter(switch=switch, port=port_number).first() + + port_profile = port.get_port_profile + + # get user_interface + user_interface = ( + Interface.objects.filter(mac_address=user_mac) + .select_related("machine__user") + .select_related("ipv4") + .first() + ) + + # get room users + room_users = User.objects.filter( + Q(club__room=port.room) | Q(adherent__room=port.room) + ) + + # get radius options + radius_option = RadiusOption.objects.first() + print(radius_option) + + EMAIL_STATE_UNVERIFIED = User.EMAIL_STATE_UNVERIFIED + RADIUS_OPTION_REJECT = RadiusOption.REJECT + serialized = serializers.PostAuthResponseSerializer( + PostAuthResponse(nas_type, room_users, port, port_profile, switch, user_interface, radius_option, EMAIL_STATE_UNVERIFIED, RADIUS_OPTION_REJECT)) + + return Response(data=serialized.data) diff --git a/radius/urls.py b/radius/urls.py new file mode 100644 index 00000000..4271f701 --- /dev/null +++ b/radius/urls.py @@ -0,0 +1,4 @@ +from . import views + +urlpatterns = [] + diff --git a/radius/views.py b/radius/views.py new file mode 100644 index 00000000..e69de29b