Add wireless authentication attributes

This commit is contained in:
jeremystretch 2021-10-20 10:58:15 -04:00
parent 0c72c20d2a
commit a66501250e
14 changed files with 252 additions and 21 deletions

View File

@ -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>

View File

@ -40,10 +40,11 @@
</table> </table>
</div> </div>
</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 %} {% plugin_left_page object %}
</div> </div>
<div class="col col-md-6"> <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' %} {% include 'inc/custom_fields_panel.html' %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>

View File

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

View File

@ -5,6 +5,7 @@ from dcim.api.serializers import NestedInterfaceSerializer
from ipam.api.serializers import NestedVLANSerializer from ipam.api.serializers import NestedVLANSerializer
from netbox.api import ChoiceField from netbox.api import ChoiceField
from netbox.api.serializers import NestedGroupModelSerializer, PrimaryModelSerializer from netbox.api.serializers import NestedGroupModelSerializer, PrimaryModelSerializer
from wireless.choices import *
from wireless.models import * from wireless.models import *
from .nested_serializers import * from .nested_serializers import *
@ -30,11 +31,13 @@ class WirelessLANGroupSerializer(NestedGroupModelSerializer):
class WirelessLANSerializer(PrimaryModelSerializer): class WirelessLANSerializer(PrimaryModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail') url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail')
vlan = NestedVLANSerializer(required=False, allow_null=True) 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: class Meta:
model = WirelessLAN model = WirelessLAN
fields = [ 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) status = ChoiceField(choices=LinkStatusChoices, required=False)
interface_a = NestedInterfaceSerializer() interface_a = NestedInterfaceSerializer()
interface_b = 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: class Meta:
model = WirelessLink model = WirelessLink
fields = [ 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',
] ]

View File

@ -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'),
)

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,7 @@ from extras.forms import CustomFieldModelFilterForm
from utilities.forms import ( from utilities.forms import (
add_blank_choice, BootstrapMixin, DynamicModelMultipleChoiceField, StaticSelect, TagFilterField, add_blank_choice, BootstrapMixin, DynamicModelMultipleChoiceField, StaticSelect, TagFilterField,
) )
from wireless.choices import *
from wireless.models import * from wireless.models import *
__all__ = ( __all__ = (
@ -52,6 +53,19 @@ class WirelessLANFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
label=_('Group'), label=_('Group'),
fetch_trigger='open' 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) tag = TagFilterField(model)
@ -74,4 +88,17 @@ class WirelessLinkFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
choices=add_blank_choice(LinkStatusChoices), choices=add_blank_choice(LinkStatusChoices),
widget=StaticSelect() 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) tag = TagFilterField(model)

View File

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

View File

@ -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),
),
]

View File

@ -8,7 +8,8 @@ from dcim.constants import WIRELESS_IFACE_TYPES
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import BigIDModel, NestedGroupModel, PrimaryModel from netbox.models import BigIDModel, NestedGroupModel, PrimaryModel
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from .constants import SSID_MAX_LENGTH from .choices import *
from .constants import *
__all__ = ( __all__ = (
'WirelessLAN', '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') @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class WirelessLANGroup(NestedGroupModel): class WirelessLANGroup(NestedGroupModel):
""" """
@ -49,12 +74,15 @@ class WirelessLANGroup(NestedGroupModel):
('parent', 'name') ('parent', 'name')
) )
def __str__(self):
return self.name
def get_absolute_url(self): def get_absolute_url(self):
return reverse('wireless:wirelesslangroup', args=[self.pk]) return reverse('wireless:wirelesslangroup', args=[self.pk])
@extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks') @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. 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') @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. A point-to-point connection between two wireless Interfaces.
""" """

View File

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