Jelajahi Sumber

Add wireless authentication attributes

jeremystretch 4 tahun lalu
induk
melakukan
a66501250e

+ 21 - 0
netbox/templates/wireless/inc/authentication_attrs.html

@@ -0,0 +1,21 @@
+{% load helpers %}
+
+<div class="card">
+  <h5 class="card-header">Authentication</h5>
+  <div class="card-body">
+    <table class="table table-hover attr-table">
+      <tr>
+          <th scope="row">Type</th>
+          <td>{{ object.get_auth_type_display|placeholder }}</td>
+      </tr>
+      <tr>
+          <th scope="row">Cipher</th>
+          <td>{{ object.get_auth_cipher_display|placeholder }}</td>
+      </tr>
+      <tr>
+          <th scope="row">PSK</th>
+          <td class="font-monospace">{{ object.auth_psk|placeholder }}</td>
+      </tr>
+    </table>
+  </div>
+</div>

+ 2 - 1
netbox/templates/wireless/wirelesslan.html

@@ -40,10 +40,11 @@
                 </table>
             </div>
         </div>
-        {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslan_list' %}
+        {% include 'wireless/inc/authentication_attrs.html' %}
         {% plugin_left_page object %}
     </div>
     <div class="col col-md-6">
+        {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslan_list' %}
         {% include 'inc/custom_fields_panel.html' %}
         {% plugin_right_page object %}
 	</div>

+ 5 - 2
netbox/templates/wireless/wirelesslink.html

@@ -17,7 +17,9 @@
           <table class="table table-hover attr-table">
             <tr>
               <th scope="row">Status</th>
-              <td>{{ object.get_status_display }}</td>
+              <td>
+                  <span class="badge bg-{{ object.get_status_class }}">{{ object.get_status_display }}</span>
+              </td>
             </tr>
             <tr>
               <th scope="row">SSID</th>
@@ -30,6 +32,7 @@
           </table>
         </div>
       </div>
+      {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslink_list' %}
       {% plugin_left_page object %}
     </div>
     <div class="col col-md-6">
@@ -39,8 +42,8 @@
           {% include 'wireless/inc/wirelesslink_interface.html' with interface=object.interface_b %}
         </div>
       </div>
+      {% include 'wireless/inc/authentication_attrs.html' %}
       {% include 'inc/custom_fields_panel.html' %}
-      {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslink_list' %}
       {% plugin_right_page object %}
     </div>
   </div>

+ 8 - 2
netbox/wireless/api/serializers.py

@@ -5,6 +5,7 @@ from dcim.api.serializers import NestedInterfaceSerializer
 from ipam.api.serializers import NestedVLANSerializer
 from netbox.api import ChoiceField
 from netbox.api.serializers import NestedGroupModelSerializer, PrimaryModelSerializer
+from wireless.choices import *
 from wireless.models import *
 from .nested_serializers import *
 
@@ -30,11 +31,13 @@ class WirelessLANGroupSerializer(NestedGroupModelSerializer):
 class WirelessLANSerializer(PrimaryModelSerializer):
     url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail')
     vlan = NestedVLANSerializer(required=False, allow_null=True)
+    auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
+    auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
 
     class Meta:
         model = WirelessLAN
         fields = [
-            'id', 'url', 'display', 'ssid', 'description', 'vlan',
+            'id', 'url', 'display', 'ssid', 'description', 'vlan', 'auth_type', 'auth_cipher', 'auth_psk',
         ]
 
 
@@ -43,9 +46,12 @@ class WirelessLinkSerializer(PrimaryModelSerializer):
     status = ChoiceField(choices=LinkStatusChoices, required=False)
     interface_a = NestedInterfaceSerializer()
     interface_b = NestedInterfaceSerializer()
+    auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
+    auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
 
     class Meta:
         model = WirelessLink
         fields = [
-            'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'description',
+            'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'description', 'auth_type',
+            'auth_cipher', 'auth_psk',
         ]

+ 26 - 0
netbox/wireless/choices.py

@@ -163,3 +163,29 @@ class WirelessChannelChoices(ChoiceSet):
             )
         ),
     )
+
+
+class WirelessAuthTypeChoices(ChoiceSet):
+    TYPE_OPEN = 'open'
+    TYPE_WEP = 'wep'
+    TYPE_WPA_PERSONAL = 'wpa-personal'
+    TYPE_WPA_ENTERPRISE = 'wpa-enterprise'
+
+    CHOICES = (
+        (TYPE_OPEN, 'Open'),
+        (TYPE_WEP, 'WEP'),
+        (TYPE_WPA_PERSONAL, 'WPA Personal (PSK)'),
+        (TYPE_WPA_ENTERPRISE, 'WPA Enterprise'),
+    )
+
+
+class WirelessAuthCipherChoices(ChoiceSet):
+    CIPHER_AUTO = 'auto'
+    CIPHER_TKIP = 'tkip'
+    CIPHER_AES = 'aes'
+
+    CHOICES = (
+        (CIPHER_AUTO, 'Auto'),
+        (CIPHER_TKIP, 'TKIP'),
+        (CIPHER_AES, 'AES'),
+    )

+ 1 - 0
netbox/wireless/constants.py

@@ -1 +1,2 @@
 SSID_MAX_LENGTH = 32  # Per IEEE 802.11-2007
+PSK_MAX_LENGTH = 64

+ 15 - 2
netbox/wireless/filtersets.py

@@ -4,6 +4,7 @@ from django.db.models import Q
 from dcim.choices import LinkStatusChoices
 from extras.filters import TagFilter
 from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet
+from .choices import *
 from .models import *
 
 __all__ = (
@@ -36,11 +37,17 @@ class WirelessLANFilterSet(PrimaryModelFilterSet):
     group_id = django_filters.ModelMultipleChoiceFilter(
         queryset=WirelessLANGroup.objects.all()
     )
+    auth_type = django_filters.MultipleChoiceFilter(
+        choices=WirelessAuthTypeChoices
+    )
+    auth_cipher = django_filters.MultipleChoiceFilter(
+        choices=WirelessAuthCipherChoices
+    )
     tag = TagFilter()
 
     class Meta:
         model = WirelessLAN
-        fields = ['id', 'ssid']
+        fields = ['id', 'ssid', 'auth_psk']
 
     def search(self, queryset, name, value):
         if not value.strip():
@@ -60,11 +67,17 @@ class WirelessLinkFilterSet(PrimaryModelFilterSet):
     status = django_filters.MultipleChoiceFilter(
         choices=LinkStatusChoices
     )
+    auth_type = django_filters.MultipleChoiceFilter(
+        choices=WirelessAuthTypeChoices
+    )
+    auth_cipher = django_filters.MultipleChoiceFilter(
+        choices=WirelessAuthCipherChoices
+    )
     tag = TagFilter()
 
     class Meta:
         model = WirelessLink
-        fields = ['id', 'ssid']
+        fields = ['id', 'ssid', 'auth_psk']
 
     def search(self, queryset, name, value):
         if not value.strip():

+ 25 - 2
netbox/wireless/forms/bulk_edit.py

@@ -4,6 +4,7 @@ from dcim.choices import LinkStatusChoices
 from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm
 from ipam.models import VLAN
 from utilities.forms import BootstrapMixin, DynamicModelChoiceField
+from wireless.choices import *
 from wireless.constants import SSID_MAX_LENGTH
 from wireless.models import *
 
@@ -52,9 +53,20 @@ class WirelessLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldMode
     description = forms.CharField(
         required=False
     )
+    auth_type = forms.ChoiceField(
+        choices=WirelessAuthTypeChoices,
+        required=False
+    )
+    auth_cipher = forms.ChoiceField(
+        choices=WirelessAuthCipherChoices,
+        required=False
+    )
+    auth_psk = forms.CharField(
+        required=False
+    )
 
     class Meta:
-        nullable_fields = ['ssid', 'group', 'vlan', 'description']
+        nullable_fields = ['ssid', 'group', 'vlan', 'description', 'auth_type', 'auth_cipher', 'auth_psk']
 
 
 class WirelessLinkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
@@ -73,6 +85,17 @@ class WirelessLinkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldMod
     description = forms.CharField(
         required=False
     )
+    auth_type = forms.ChoiceField(
+        choices=WirelessAuthTypeChoices,
+        required=False
+    )
+    auth_cipher = forms.ChoiceField(
+        choices=WirelessAuthCipherChoices,
+        required=False
+    )
+    auth_psk = forms.CharField(
+        required=False
+    )
 
     class Meta:
-        nullable_fields = ['ssid', 'description']
+        nullable_fields = ['ssid', 'description', 'auth_type', 'auth_cipher', 'auth_psk']

+ 23 - 2
netbox/wireless/forms/bulk_import.py

@@ -3,6 +3,7 @@ from dcim.models import Interface
 from extras.forms import CustomFieldModelCSVForm
 from ipam.models import VLAN
 from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
+from wireless.choices import *
 from wireless.models import *
 
 __all__ = (
@@ -38,10 +39,20 @@ class WirelessLANCSVForm(CustomFieldModelCSVForm):
         to_field_name='name',
         help_text='Bridged VLAN'
     )
+    auth_type = CSVChoiceField(
+        choices=WirelessAuthTypeChoices,
+        required=False,
+        help_text='Authentication type'
+    )
+    auth_cipher = CSVChoiceField(
+        choices=WirelessAuthCipherChoices,
+        required=False,
+        help_text='Authentication cipher'
+    )
 
     class Meta:
         model = WirelessLAN
-        fields = ('ssid', 'group', 'description', 'vlan')
+        fields = ('ssid', 'group', 'description', 'vlan', 'auth_type', 'auth_cipher', 'auth_psk')
 
 
 class WirelessLinkCSVForm(CustomFieldModelCSVForm):
@@ -55,7 +66,17 @@ class WirelessLinkCSVForm(CustomFieldModelCSVForm):
     interface_b = CSVModelChoiceField(
         queryset=Interface.objects.all()
     )
+    auth_type = CSVChoiceField(
+        choices=WirelessAuthTypeChoices,
+        required=False,
+        help_text='Authentication type'
+    )
+    auth_cipher = CSVChoiceField(
+        choices=WirelessAuthCipherChoices,
+        required=False,
+        help_text='Authentication cipher'
+    )
 
     class Meta:
         model = WirelessLink
-        fields = ('interface_a', 'interface_b', 'ssid', 'description')
+        fields = ('interface_a', 'interface_b', 'ssid', 'description', 'auth_type', 'auth_cipher', 'auth_psk')

+ 27 - 0
netbox/wireless/forms/filtersets.py

@@ -6,6 +6,7 @@ from extras.forms import CustomFieldModelFilterForm
 from utilities.forms import (
     add_blank_choice, BootstrapMixin, DynamicModelMultipleChoiceField, StaticSelect, TagFilterField,
 )
+from wireless.choices import *
 from wireless.models import *
 
 __all__ = (
@@ -52,6 +53,19 @@ class WirelessLANFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
         label=_('Group'),
         fetch_trigger='open'
     )
+    auth_type = forms.ChoiceField(
+        required=False,
+        choices=add_blank_choice(WirelessAuthTypeChoices),
+        widget=StaticSelect()
+    )
+    auth_cipher = forms.ChoiceField(
+        required=False,
+        choices=add_blank_choice(WirelessAuthCipherChoices),
+        widget=StaticSelect()
+    )
+    auth_psk = forms.CharField(
+        required=False
+    )
     tag = TagFilterField(model)
 
 
@@ -74,4 +88,17 @@ class WirelessLinkFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
         choices=add_blank_choice(LinkStatusChoices),
         widget=StaticSelect()
     )
+    auth_type = forms.ChoiceField(
+        required=False,
+        choices=add_blank_choice(WirelessAuthTypeChoices),
+        widget=StaticSelect()
+    )
+    auth_cipher = forms.ChoiceField(
+        required=False,
+        choices=add_blank_choice(WirelessAuthCipherChoices),
+        widget=StaticSelect()
+    )
+    auth_psk = forms.CharField(
+        required=False
+    )
     tag = TagFilterField(model)

+ 16 - 3
netbox/wireless/forms/models.py

@@ -35,7 +35,8 @@ class WirelessLANForm(BootstrapMixin, CustomFieldModelForm):
     )
     vlan = DynamicModelChoiceField(
         queryset=VLAN.objects.all(),
-        required=False
+        required=False,
+        label='VLAN'
     )
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
@@ -45,12 +46,17 @@ class WirelessLANForm(BootstrapMixin, CustomFieldModelForm):
     class Meta:
         model = WirelessLAN
         fields = [
-            'ssid', 'group', 'description', 'vlan', 'tags',
+            'ssid', 'group', 'description', 'vlan', 'auth_type', 'auth_cipher', 'auth_psk', 'tags',
         ]
         fieldsets = (
             ('Wireless LAN', ('ssid', 'group', 'description', 'tags')),
             ('VLAN', ('vlan',)),
+            ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
         )
+        widgets = {
+            'auth_type': StaticSelect,
+            'auth_cipher': StaticSelect,
+        }
 
 
 class WirelessLinkForm(BootstrapMixin, CustomFieldModelForm):
@@ -94,8 +100,15 @@ class WirelessLinkForm(BootstrapMixin, CustomFieldModelForm):
     class Meta:
         model = WirelessLink
         fields = [
-            'device_a', 'interface_a', 'device_b', 'interface_b', 'status', 'ssid', 'description', 'tags',
+            'device_a', 'interface_a', 'device_b', 'interface_b', 'status', 'ssid', 'description', 'auth_type',
+            'auth_cipher', 'auth_psk', 'tags',
         ]
+        fieldsets = (
+            ('Link', ('device_a', 'interface_a', 'device_b', 'interface_b', 'status', 'ssid', 'description', 'tags')),
+            ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')),
+        )
         widgets = {
             'status': StaticSelect,
+            'auth_type': StaticSelect,
+            'auth_cipher': StaticSelect,
         }

+ 41 - 0
netbox/wireless/migrations/0002_wireless_auth.py

@@ -0,0 +1,41 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('wireless', '0001_wireless'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='wirelesslan',
+            name='auth_cipher',
+            field=models.CharField(blank=True, max_length=50),
+        ),
+        migrations.AddField(
+            model_name='wirelesslan',
+            name='auth_psk',
+            field=models.CharField(blank=True, max_length=64),
+        ),
+        migrations.AddField(
+            model_name='wirelesslan',
+            name='auth_type',
+            field=models.CharField(blank=True, max_length=50),
+        ),
+        migrations.AddField(
+            model_name='wirelesslink',
+            name='auth_cipher',
+            field=models.CharField(blank=True, max_length=50),
+        ),
+        migrations.AddField(
+            model_name='wirelesslink',
+            name='auth_psk',
+            field=models.CharField(blank=True, max_length=64),
+        ),
+        migrations.AddField(
+            model_name='wirelesslink',
+            name='auth_type',
+            field=models.CharField(blank=True, max_length=50),
+        ),
+    ]

+ 31 - 3
netbox/wireless/models.py

@@ -8,7 +8,8 @@ from dcim.constants import WIRELESS_IFACE_TYPES
 from extras.utils import extras_features
 from netbox.models import BigIDModel, NestedGroupModel, PrimaryModel
 from utilities.querysets import RestrictedQuerySet
-from .constants import SSID_MAX_LENGTH
+from .choices import *
+from .constants import *
 
 __all__ = (
     'WirelessLAN',
@@ -17,6 +18,30 @@ __all__ = (
 )
 
 
+class WirelessAuthenticationBase(models.Model):
+    """
+    Abstract model for attaching attributes related to wireless authentication.
+    """
+    auth_type = models.CharField(
+        max_length=50,
+        choices=WirelessAuthTypeChoices,
+        blank=True
+    )
+    auth_cipher = models.CharField(
+        max_length=50,
+        choices=WirelessAuthCipherChoices,
+        blank=True
+    )
+    auth_psk = models.CharField(
+        max_length=PSK_MAX_LENGTH,
+        blank=True,
+        verbose_name='Pre-shared key'
+    )
+
+    class Meta:
+        abstract = True
+
+
 @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
 class WirelessLANGroup(NestedGroupModel):
     """
@@ -49,12 +74,15 @@ class WirelessLANGroup(NestedGroupModel):
             ('parent', 'name')
         )
 
+    def __str__(self):
+        return self.name
+
     def get_absolute_url(self):
         return reverse('wireless:wirelesslangroup', args=[self.pk])
 
 
 @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks')
-class WirelessLAN(PrimaryModel):
+class WirelessLAN(WirelessAuthenticationBase, PrimaryModel):
     """
     A wireless network formed among an arbitrary number of access point and clients.
     """
@@ -95,7 +123,7 @@ class WirelessLAN(PrimaryModel):
 
 
 @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks')
-class WirelessLink(PrimaryModel):
+class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
     """
     A point-to-point connection between two wireless Interfaces.
     """

+ 11 - 4
netbox/wireless/tables.py

@@ -48,8 +48,11 @@ class WirelessLANTable(BaseTable):
 
     class Meta(BaseTable.Meta):
         model = WirelessLAN
-        fields = ('pk', 'ssid', 'group', 'description', 'vlan', 'interface_count', 'tags')
-        default_columns = ('pk', 'ssid', 'group', 'description', 'vlan', 'interface_count')
+        fields = (
+            'pk', 'ssid', 'group', 'description', 'vlan', 'interface_count', 'auth_type', 'auth_cipher', 'auth_psk',
+            'tags',
+        )
+        default_columns = ('pk', 'ssid', 'group', 'description', 'vlan', 'auth_type', 'interface_count')
 
 
 class WirelessLANInterfacesTable(BaseTable):
@@ -94,7 +97,11 @@ class WirelessLinkTable(BaseTable):
 
     class Meta(BaseTable.Meta):
         model = WirelessLink
-        fields = ('pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'description')
-        default_columns = (
+        fields = (
             'pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'description',
+            'auth_type', 'auth_cipher', 'auth_psk', 'tags',
+        )
+        default_columns = (
+            'pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'auth_type',
+            'description',
         )