diff --git a/netbox/templates/wireless/inc/authentication_attrs.html b/netbox/templates/wireless/inc/authentication_attrs.html
new file mode 100644
index 000000000..ed4c7546c
--- /dev/null
+++ b/netbox/templates/wireless/inc/authentication_attrs.html
@@ -0,0 +1,21 @@
+{% load helpers %}
+
+
+
+
+
+
+ Type |
+ {{ object.get_auth_type_display|placeholder }} |
+
+
+ Cipher |
+ {{ object.get_auth_cipher_display|placeholder }} |
+
+
+ PSK |
+ {{ object.auth_psk|placeholder }} |
+
+
+
+
diff --git a/netbox/templates/wireless/wirelesslan.html b/netbox/templates/wireless/wirelesslan.html
index cfe13ca45..5c6784de4 100644
--- a/netbox/templates/wireless/wirelesslan.html
+++ b/netbox/templates/wireless/wirelesslan.html
@@ -40,10 +40,11 @@
- {% 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 %}
+ {% 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 %}
diff --git a/netbox/templates/wireless/wirelesslink.html b/netbox/templates/wireless/wirelesslink.html
index 45ec6b0c9..afdeff357 100644
--- a/netbox/templates/wireless/wirelesslink.html
+++ b/netbox/templates/wireless/wirelesslink.html
@@ -17,7 +17,9 @@
Status |
- {{ object.get_status_display }} |
+
+ {{ object.get_status_display }}
+ |
SSID |
@@ -30,6 +32,7 @@
+ {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslink_list' %}
{% plugin_left_page object %}
@@ -39,8 +42,8 @@
{% include 'wireless/inc/wirelesslink_interface.html' with interface=object.interface_b %}
+ {% 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 %}
diff --git a/netbox/wireless/api/serializers.py b/netbox/wireless/api/serializers.py
index 24395b77c..e9be35618 100644
--- a/netbox/wireless/api/serializers.py
+++ b/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',
]
diff --git a/netbox/wireless/choices.py b/netbox/wireless/choices.py
index 8a710b532..c8e7fd09f 100644
--- a/netbox/wireless/choices.py
+++ b/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'),
+ )
diff --git a/netbox/wireless/constants.py b/netbox/wireless/constants.py
index 188c4abd9..63de2b136 100644
--- a/netbox/wireless/constants.py
+++ b/netbox/wireless/constants.py
@@ -1 +1,2 @@
SSID_MAX_LENGTH = 32 # Per IEEE 802.11-2007
+PSK_MAX_LENGTH = 64
diff --git a/netbox/wireless/filtersets.py b/netbox/wireless/filtersets.py
index a5d9b7d75..cc67c1fc3 100644
--- a/netbox/wireless/filtersets.py
+++ b/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():
diff --git a/netbox/wireless/forms/bulk_edit.py b/netbox/wireless/forms/bulk_edit.py
index c0d5a925e..1da98026c 100644
--- a/netbox/wireless/forms/bulk_edit.py
+++ b/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']
diff --git a/netbox/wireless/forms/bulk_import.py b/netbox/wireless/forms/bulk_import.py
index 6b22728f6..e9e9afed6 100644
--- a/netbox/wireless/forms/bulk_import.py
+++ b/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')
diff --git a/netbox/wireless/forms/filtersets.py b/netbox/wireless/forms/filtersets.py
index 13aae99a5..483d74a7c 100644
--- a/netbox/wireless/forms/filtersets.py
+++ b/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)
diff --git a/netbox/wireless/forms/models.py b/netbox/wireless/forms/models.py
index 9a7b78b31..aa453ba64 100644
--- a/netbox/wireless/forms/models.py
+++ b/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,
}
diff --git a/netbox/wireless/migrations/0002_wireless_auth.py b/netbox/wireless/migrations/0002_wireless_auth.py
new file mode 100644
index 000000000..9ca4e351c
--- /dev/null
+++ b/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),
+ ),
+ ]
diff --git a/netbox/wireless/models.py b/netbox/wireless/models.py
index b0cacde15..43818279e 100644
--- a/netbox/wireless/models.py
+++ b/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.
"""
diff --git a/netbox/wireless/tables.py b/netbox/wireless/tables.py
index 486fa2a71..ec8f3ddd2 100644
--- a/netbox/wireless/tables.py
+++ b/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',
)