|
|
@@ -4,17 +4,20 @@ import os
|
|
|
from django.contrib.auth.models import Group, User
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
from django.contrib.postgres.fields import ArrayField
|
|
|
+from django.core.exceptions import ValidationError
|
|
|
from django.core.validators import MinLengthValidator
|
|
|
from django.db import models
|
|
|
from django.db.models.signals import post_save
|
|
|
from django.dispatch import receiver
|
|
|
from django.utils import timezone
|
|
|
|
|
|
+from ipam.fields import IPNetworkField
|
|
|
from netbox.config import get_config
|
|
|
from utilities.querysets import RestrictedQuerySet
|
|
|
from utilities.utils import flatten_dict
|
|
|
from .constants import *
|
|
|
|
|
|
+import ipaddress
|
|
|
|
|
|
__all__ = (
|
|
|
'ObjectPermission',
|
|
|
@@ -216,6 +219,12 @@ class Token(models.Model):
|
|
|
max_length=200,
|
|
|
blank=True
|
|
|
)
|
|
|
+ allowed_ips = ArrayField(
|
|
|
+ base_field=IPNetworkField(),
|
|
|
+ blank=True,
|
|
|
+ null=True,
|
|
|
+ help_text='Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. Ex: "10.1.1.0/24, 192.168.10.16/32, 2001:DB8:1::/64"',
|
|
|
+ )
|
|
|
|
|
|
class Meta:
|
|
|
pass
|
|
|
@@ -240,6 +249,24 @@ class Token(models.Model):
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
+ def validate_client_ip(self, raw_ip_address):
|
|
|
+ """
|
|
|
+ Checks that an IP address falls within the allowed IPs.
|
|
|
+ """
|
|
|
+ if not self.allowed_ips:
|
|
|
+ return True
|
|
|
+
|
|
|
+ try:
|
|
|
+ ip_address = ipaddress.ip_address(raw_ip_address)
|
|
|
+ except ValueError as e:
|
|
|
+ raise ValidationError(str(e))
|
|
|
+
|
|
|
+ for ip_network in self.allowed_ips:
|
|
|
+ if ip_address in ipaddress.ip_network(ip_network):
|
|
|
+ return True
|
|
|
+
|
|
|
+ return False
|
|
|
+
|
|
|
|
|
|
#
|
|
|
# Permissions
|