From f9b7d70314e10838bedbd201106337f0eb00ccf3 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Tue, 10 Sep 2019 19:11:14 +0200 Subject: [PATCH] Fix various bugs in auth.py. --- freeradius_utils/auth.py | 39 ++++++++++++------- ...tributes.py => 0062_auto_20190910_1909.py} | 3 +- preferences/models.py | 31 +++------------ topologie/models.py | 12 +++--- 4 files changed, 36 insertions(+), 49 deletions(-) rename preferences/migrations/{0062_radius_attributes.py => 0062_auto_20190910_1909.py} (88%) diff --git a/freeradius_utils/auth.py b/freeradius_utils/auth.py index 1c74303d..c2cb3fed 100644 --- a/freeradius_utils/auth.py +++ b/freeradius_utils/auth.py @@ -117,8 +117,11 @@ def radius_event(fun): # (str,str) : rlm_python ne digère PAS les unicodes return fun(data) except Exception as err: + exc_type, exc_instance, exc_traceback = sys.exc_info() + formatted_traceback = ''.join(traceback.format_tb( + exc_traceback)) logger.error('Failed %r on data %r' % (err, auth_data)) - logger.debug('Function %r, Traceback: %s' % (fun, repr(traceback.format_stack()))) + logger.error('Function %r, Traceback : %r' % (fun, formatted_traceback)) return radiusd.RLM_MODULE_FAIL return new_f @@ -243,7 +246,7 @@ def post_auth(data): ("Tunnel-Type", "VLAN"), ("Tunnel-Medium-Type", "IEEE-802"), ("Tunnel-Private-Group-Id", '%d' % int(vlan_id)), - ) + attributes, + ) + tuple(attributes), () ) else: @@ -256,7 +259,7 @@ def post_auth(data): return ( radiusd.RLM_MODULE_REJECT, - attributes, + tuple(attributes), () ) @@ -369,6 +372,10 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, - decision (bool) - Attributs supplémentaires (attribut:str, operateur:str, valeur:str) """ + attributes_kwargs = { + 'client_mac' : str(mac_address), + 'switch_port' : str(port_number), + } # Get port from switch and port number extra_log = "" # Si le NAS est inconnu, on place sur le vlan defaut @@ -379,14 +386,16 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Nas inconnu', RadiusOption.get_cached_value('vlan_decision_ok').vlan_id, True, - RadiusOption.get_attributes('ok_attributes') + RadiusOption.get_attributes('ok_attributes', attributes_kwargs) ) sw_name = str(getattr(nas_machine, 'short_name', str(nas_machine))) + switch = Switch.objects.filter(machine_ptr=nas_machine).first() + attributes_kwargs['switch_ip'] = str(switch.ipv4) port = (Port.objects .filter( - switch=Switch.objects.filter(machine_ptr=nas_machine), + switch=switch, port=port_number ) .first()) @@ -401,7 +410,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Port inconnu', getattr(RadiusOption.get_cached_value('unknown_port_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_port')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_port_attributes') + RadiusOption.get_attributes('unknown_port_attributes', attributes_kwargs) ) # On récupère le profil du port @@ -415,7 +424,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, attributes = () else: DECISION_VLAN = RadiusOption.get_cached_value('vlan_decision_ok').vlan_id - attributes = RadiusOption.get_attributes('ok_attributes') + attributes = RadiusOption.get_attributes('ok_attributes', attributes_kwargs) # Si le port est désactivé, on rejette la connexion if not port.state: @@ -460,7 +469,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Chambre inconnue', getattr(RadiusOption.get_cached_value('unknown_room_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_room')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_room_attributes'), + RadiusOption.get_attributes('unknown_room_attributes', attributes_kwargs), ) room_user = User.objects.filter( @@ -473,7 +482,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Chambre non cotisante', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes'), + RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ) for user in room_user: if user.is_ban() or user.state != User.STATE_ACTIVE: @@ -483,7 +492,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Utilisateur banni ou desactive', getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, - RadiusOption.get_attributes('banned_attributes'), + RadiusOption.get_attributes('banned_attributes', attributes_kwargs), ) elif not (user.is_connected() or user.is_whitelisted()): return ( @@ -492,7 +501,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Utilisateur non cotisant', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes'), + RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ) # else: user OK, on passe à la verif MAC @@ -516,7 +525,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Machine Inconnue', getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_machine_attributes'), + RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), ) # Sinon on bascule sur la politique définie dans les options # radius. @@ -527,7 +536,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Machine inconnue', getattr(RadiusOption.get_cached_value('unknown_machine_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('unknown_machine')!= RadiusOption.REJECT, - RadiusOption.get_attributes('unknown_machine_attributes'), + RadiusOption.get_attributes('unknown_machine_attributes', attributes_kwargs), ) # L'interface a été trouvée, on vérifie qu'elle est active, @@ -543,7 +552,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Adherent banni', getattr(RadiusOption.get_cached_value('banned_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('banned')!= RadiusOption.REJECT, - RadiusOption.get_attributes('banned_attributes'), + RadiusOption.get_attributes('banned_attributes', attributes_kwargs), ) if not interface.is_active: return ( @@ -552,7 +561,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, u'Machine non active / adherent non cotisant', getattr(RadiusOption.get_cached_value('non_member_vlan'), 'vlan_id', None), RadiusOption.get_cached_value('non_member')!= RadiusOption.REJECT, - RadiusOption.get_attributes('non_member_attributes'), + RadiusOption.get_attributes('non_member_attributes', attributes_kwargs), ) # Si on choisi de placer les machines sur le vlan # correspondant à leur type : diff --git a/preferences/migrations/0062_radius_attributes.py b/preferences/migrations/0062_auto_20190910_1909.py similarity index 88% rename from preferences/migrations/0062_radius_attributes.py rename to preferences/migrations/0062_auto_20190910_1909.py index 05a34493..d121ba7c 100644 --- a/preferences/migrations/0062_radius_attributes.py +++ b/preferences/migrations/0062_auto_20190910_1909.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.23 on 2019-09-09 14:13 +# Generated by Django 1.11.23 on 2019-09-10 17:09 from __future__ import unicode_literals from django.db import migrations, models @@ -18,7 +18,6 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('attribute', models.CharField(help_text='See http://freeradius.org/rfc/attributes.html', max_length=255, verbose_name='Attribute')), - ('operator', models.CharField(choices=[('=', '='), (':=', ':='), ('==', '=='), ('+=', '+='), ('!=', '!='), ('>', '>'), ('>=', '>='), ('<', '<'), ('<=', '<='), ('=~', '=~'), ('!~', '!~'), ('=*', '=*'), ('!*', '!*')], default=':=', help_text='See https://wiki.freeradius.org/config/Operators', max_length=2, verbose_name='Operator')), ('value', models.CharField(max_length=255, verbose_name='Value')), ('comment', models.TextField(blank=True, default='', help_text='Use this field to document this attribute.', verbose_name='Comment')), ], diff --git a/preferences/models.py b/preferences/models.py index 098d9b18..f5309b01 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -596,33 +596,11 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): verbose_name = _("RADIUS attribute") verbose_name_plural = _("RADIUS attributes") - CHOICE_OPERATOR = ( - ('=' , '=' ), - (':=', ':='), - ('==', '=='), - ('+=', '+='), - ('!=', '!='), - ('>' , '>' ), - ('>=', '>='), - ('<' , '<' ), - ('<=', '<='), - ('=~', '=~'), - ('!~', '!~'), - ('=*', '=*'), - ('!*', '!*') - ) attribute = models.CharField( max_length=255, verbose_name=_("Attribute"), help_text=_("See http://freeradius.org/rfc/attributes.html"), ) - operator = models.CharField( - max_length=2, - verbose_name=_("Operator"), - help_text=_("See https://wiki.freeradius.org/config/Operators"), - choices=CHOICE_OPERATOR, - default=':=' - ) value = models.CharField( max_length=255, verbose_name=_("Value") @@ -637,8 +615,6 @@ class RadiusAttribute(RevMixin, AclMixin, models.Model): def __str__(self): return ' '.join([self.attribute, self.operator, self.value]) - def as_tuple(self): - return (self.attribute, self.operator, self.value) class RadiusOption(AclMixin, PreferencesModel): @@ -790,9 +766,12 @@ class RadiusOption(AclMixin, PreferencesModel): ) @classmethod - def get_attributes(cls, name): + def get_attributes(cls, name, attribute_kwargs={}): return ( - attribute.as_tuple() + ( + str(attribute.attribute), + str(attribute.value % attribute_kwargs) + ) for attribute in cls.get_cached_value(name).all() ) diff --git a/topologie/models.py b/topologie/models.py index 250e52a9..235b3885 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -400,17 +400,17 @@ class Switch(AclMixin, Machine): def profile_type_or_nothing(self, profile_type): """Return the profile for a profile_type of this switch - + If exists, returns the defined default profile for a profile type on the dormitory which the switch belongs - + Otherwise, returns the nothing profile""" profile_queryset = PortProfile.objects.filter(profil_default=profile_type) if self.get_dormitory: port_profile = profile_queryset.filter(on_dormitory=self.get_dormitory).first() or profile_queryset.first() else: port_profile = profile_queryset.first() - return port_profile or Switch.nothing_profile + return port_profile or Switch.nothing_profile() @cached_property def default_uplink_profile(self): @@ -628,7 +628,7 @@ class Building(AclMixin, RevMixin, models.Model): @cached_property def cached_name(self): - return self.get_name() + return self.get_name() def __str__(self): return self.cached_name @@ -712,7 +712,7 @@ class Port(AclMixin, RevMixin, models.Model): def get_port_profile(self): """Return the config profil for this port :returns: the profile of self (port) - + If is defined a custom profile, returns it elIf a default profile is defined for its dormitory, returns it Else, returns the global default profil @@ -730,7 +730,7 @@ class Port(AclMixin, RevMixin, models.Model): elif self.room: return self.switch.default_room_profile else: - return Switch.nothing_profile + return Switch.nothing_profile() @classmethod def get_instance(cls, portid, *_args, **kwargs):