mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
handle bogon asns (#419)
This commit is contained in:
@ -5,9 +5,38 @@ import rdap
|
||||
from rdap import RdapAsn
|
||||
from rdap.exceptions import RdapException, RdapHTTPError, RdapNotFoundError
|
||||
import requests
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from peeringdb_server import settings
|
||||
|
||||
BOGON_ASN_RANGES = [
|
||||
# RFC 5398 - documentation 16-bit
|
||||
(64496, 64511),
|
||||
# RFC 5398 - documentation 32-bit
|
||||
(65536, 65551),
|
||||
# RFC 6996 - private 16-bit
|
||||
(64512, 65534),
|
||||
# RFC 6996 - private 32-bit
|
||||
(4200000000, 4294967294),
|
||||
]
|
||||
|
||||
class BogonAsn(rdap.RdapAsn):
|
||||
|
||||
"""
|
||||
On tutorial mode environments we will return an instance
|
||||
of this to provide an rdapasn result for asns in the
|
||||
private and documentation ranges
|
||||
"""
|
||||
|
||||
def __init__(self, asn):
|
||||
name = "AS{}".format(asn)
|
||||
self._parsed = {
|
||||
"name":name,
|
||||
"org_name":name,
|
||||
"org_address":None,
|
||||
"emails":[]
|
||||
}
|
||||
|
||||
|
||||
class RdapLookup(rdap.RdapClient):
|
||||
"""
|
||||
@ -23,6 +52,42 @@ class RdapLookup(rdap.RdapClient):
|
||||
super(RdapLookup, self).__init__(config)
|
||||
|
||||
|
||||
def get_asn(self, asn):
|
||||
"""
|
||||
We handle asns that fall into the private/documentation ranges
|
||||
manually - others are processed normally through rdap lookup
|
||||
"""
|
||||
|
||||
if asn_is_bogon(asn):
|
||||
if settings.TUTORIAL_MODE:
|
||||
return BogonAsn(asn)
|
||||
else:
|
||||
raise RdapException(_("ASNs for documentation/private purposes " \
|
||||
"are not allowed in this environment"))
|
||||
return super(RdapLookup, self).get_asn(asn)
|
||||
|
||||
|
||||
|
||||
def asn_is_bogon(asn):
|
||||
"""
|
||||
Test if an asn is bogon by being either in the documentation
|
||||
or private asn ranges
|
||||
|
||||
Arguments:
|
||||
- asn<int>
|
||||
|
||||
Return:
|
||||
- bool: True if in bogon range
|
||||
"""
|
||||
|
||||
asn = int(asn)
|
||||
for as_range in BOGON_ASN_RANGES:
|
||||
if asn >= as_range[0] and asn <= as_range[1]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def network_is_bogon(network):
|
||||
"""
|
||||
Returns if the passed ipaddress network is a bogon
|
||||
|
@ -27,6 +27,7 @@ from peeringdb_server.models import (
|
||||
IXLanPrefix, InternetExchangeFacility)
|
||||
|
||||
from peeringdb_server.serializers import REFTAG_MAP as REFTAG_MAP_SLZ
|
||||
from peeringdb_server import inet, settings as pdb_settings
|
||||
|
||||
START_TIMESTAMP = time.time()
|
||||
|
||||
@ -1033,6 +1034,32 @@ class TestJSON(unittest.TestCase):
|
||||
|
||||
##########################################################################
|
||||
|
||||
def test_org_admin_002_POST_net_bogon_asn(self):
|
||||
|
||||
# Test bogon asn failure
|
||||
|
||||
data = self.make_data_net()
|
||||
for bogon_asn in inet.BOGON_ASN_RANGES:
|
||||
r_data = self.assert_create(
|
||||
self.db_org_admin, "net", data,
|
||||
test_failures={"invalid": {
|
||||
"asn": bogon_asn[0]
|
||||
}}, test_success=False)
|
||||
|
||||
# server running in tutorial mode should be allowed
|
||||
# to create networks with bogon asns, so we test that
|
||||
# as well
|
||||
|
||||
pdb_settings.TUTORIAL_MODE = True
|
||||
|
||||
for bogon_asn in inet.BOGON_ASN_RANGES:
|
||||
data = self.make_data_net(asn=bogon_asn[0])
|
||||
r_data = self.assert_create(self.db_org_admin, "net", data)
|
||||
|
||||
pdb_settings.TUTORIAL_MODE = False
|
||||
|
||||
##########################################################################
|
||||
|
||||
def test_org_admin_002_PUT_net_write_only_fields(self):
|
||||
"""
|
||||
with this we check that certain fields that are allowed to be
|
||||
|
@ -199,9 +199,8 @@ def uoar_creation(sender, instance, created=False, **kwargs):
|
||||
rdap_lookup = rdap = RdapLookup().get_asn(instance.asn)
|
||||
ok = rdap_lookup.emails
|
||||
except RdapException, inst:
|
||||
if not pdb_settings.AUTO_APPROVE_AFFILIATION:
|
||||
instance.deny()
|
||||
raise
|
||||
instance.deny()
|
||||
raise
|
||||
|
||||
# create organization
|
||||
instance.org, org_created = Organization.create_from_rdap(
|
||||
|
@ -156,7 +156,7 @@ settings.configure(
|
||||
DATA_QUALITY_MAX_PREFIX_V6_LIMIT=500000,
|
||||
TUTORIAL_MODE=False,
|
||||
RATELIMITS={
|
||||
"view_affiliate_to_org_POST": "3/m",
|
||||
"view_affiliate_to_org_POST": "100/m",
|
||||
"resend_confirmation_mail": "2/m",
|
||||
"view_request_ownership_GET": "3/m",
|
||||
"view_username_retrieve_initiate": "2/m",
|
||||
|
@ -41,6 +41,8 @@ def setup_module(module):
|
||||
def get_asn(self, asn):
|
||||
if asn in ASN_RANGE_OVERRIDE:
|
||||
return pdbinet.RdapAsn(self.override_result)
|
||||
elif pdbinet.asn_is_bogon(asn):
|
||||
return RdapLookup_get_asn(self, asn)
|
||||
else:
|
||||
raise pdbinet.RdapNotFoundError()
|
||||
|
||||
|
@ -3,12 +3,16 @@ import json
|
||||
import pytest
|
||||
import peeringdb_server.models as models
|
||||
import peeringdb_server.views as pdbviews
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.test import TestCase, Client, RequestFactory
|
||||
|
||||
import peeringdb_server.inet as pdbinet
|
||||
from util import SettingsCase
|
||||
|
||||
ERR_COULD_NOT_GET_RIR_ENTRY = "RDAP Lookup Error: Test Not Found"
|
||||
ERR_BOGON_ASN = "RDAP Lookup Error: ASNs for documentation/private purposes " \
|
||||
"are not allowed in this environment"
|
||||
|
||||
RdapLookup_get_asn = pdbinet.RdapLookup.get_asn
|
||||
|
||||
@ -39,6 +43,8 @@ def setup_module(module):
|
||||
r._parsed["name"] = "AS%d" % asn
|
||||
r._parsed["org_name"] = "ORG AS%d" % asn
|
||||
return r
|
||||
elif pdbinet.asn_is_bogon(asn):
|
||||
return RdapLookup_get_asn(self, asn)
|
||||
else:
|
||||
raise pdbinet.RdapNotFoundError("Test Not Found")
|
||||
|
||||
@ -204,6 +210,24 @@ class AsnAutomationTestCase(TestCase):
|
||||
self.assertEqual(net.status, "ok")
|
||||
self.assertEqual(net.org.status, "ok")
|
||||
|
||||
def test_affiliate_to_bogon_asn(self):
|
||||
"""
|
||||
tests affiliation with non-existant asn
|
||||
"""
|
||||
asns = []
|
||||
for a,b in pdbinet.BOGON_ASN_RANGES:
|
||||
asns.extend([a,b])
|
||||
|
||||
for asn in asns:
|
||||
request = self.factory.post("/affiliate-to-org", data={
|
||||
"asn": asn})
|
||||
|
||||
request.user = self.user_a
|
||||
request._dont_enforce_csrf_checks = True
|
||||
resp = json.loads(pdbviews.view_affiliate_to_org(request).content)
|
||||
self.assertEqual(resp.get("asn"), ERR_BOGON_ASN)
|
||||
|
||||
|
||||
def test_claim_ownership(self):
|
||||
"""
|
||||
tests ownership to org via asn RiR validation
|
||||
@ -243,3 +267,31 @@ class AsnAutomationTestCase(TestCase):
|
||||
self.assertEqual(
|
||||
self.user_b.groups.filter(name=org.admin_usergroup.name).exists(),
|
||||
False)
|
||||
|
||||
class TestTutorialMode(SettingsCase):
|
||||
settings = {"TUTORIAL_MODE":True}
|
||||
|
||||
def setUp(self):
|
||||
super(TestTutorialMode, self).setUp()
|
||||
self.factory = RequestFactory()
|
||||
|
||||
def test_affiliate_to_bogon_asn(self):
|
||||
"""
|
||||
tests affiliation with non-existant bogon asn
|
||||
with tutorial mode enabled those should be allowed
|
||||
"""
|
||||
user = get_user_model().objects.create_user("user_a", "user_a@localhost", "user_a")
|
||||
asns = []
|
||||
for a,b in pdbinet.BOGON_ASN_RANGES:
|
||||
asns.extend([a,b])
|
||||
|
||||
for asn in asns:
|
||||
request = self.factory.post("/affiliate-to-org", data={
|
||||
"asn": asn})
|
||||
|
||||
request.user = user
|
||||
request._dont_enforce_csrf_checks = True
|
||||
resp = json.loads(pdbviews.view_affiliate_to_org(request).content)
|
||||
self.assertEqual(resp.get("status"), "ok")
|
||||
|
||||
|
||||
|
@ -3,36 +3,11 @@ from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
from util import ClientCase
|
||||
from util import SettingsCase
|
||||
from peeringdb_server import signals, models, serializers
|
||||
from peeringdb_server import settings as pdb_settings
|
||||
|
||||
|
||||
class SettingsCase(ClientCase):
|
||||
|
||||
"""
|
||||
Since we read settings from peeringdb_server.settings
|
||||
we can't use the `settings` fixture from pytest-django
|
||||
|
||||
This class instead does something similar for peeringdb_server.settings,
|
||||
where it will override settings specified and then reset after test case
|
||||
is finished
|
||||
"""
|
||||
|
||||
settings = {}
|
||||
|
||||
@classmethod
|
||||
def setUp(cls):
|
||||
cls._restore = {}
|
||||
for k,v in cls.settings.items():
|
||||
cls._restore[k] = getattr(pdb_settings, k)
|
||||
setattr(pdb_settings, k, v)
|
||||
|
||||
@classmethod
|
||||
def tearDown(cls):
|
||||
for k,v in cls._restore.items():
|
||||
setattr(pdb_settings, k, v)
|
||||
|
||||
|
||||
class TestAutoVerifyUser(SettingsCase):
|
||||
settings = {"AUTO_VERIFY_USERS":True}
|
||||
|
@ -1,7 +1,9 @@
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth.models import Group, AnonymousUser
|
||||
from django.conf import settings
|
||||
import peeringdb_server.models as models
|
||||
import django_namespace_perms as nsp
|
||||
from peeringdb_server import settings as pdb_settings
|
||||
|
||||
|
||||
class ClientCase(TestCase):
|
||||
@ -33,3 +35,31 @@ class ClientCase(TestCase):
|
||||
group=guest_group,
|
||||
namespace="peeringdb.organization.*.network.*.poc_set.public",
|
||||
permissions=0x01)
|
||||
|
||||
|
||||
class SettingsCase(ClientCase):
|
||||
|
||||
"""
|
||||
Since we read settings from peeringdb_server.settings
|
||||
we can't use the `settings` fixture from pytest-django
|
||||
|
||||
This class instead does something similar for peeringdb_server.settings,
|
||||
where it will override settings specified and then reset after test case
|
||||
is finished
|
||||
"""
|
||||
|
||||
settings = {}
|
||||
|
||||
@classmethod
|
||||
def setUp(cls):
|
||||
cls._restore = {}
|
||||
for k,v in cls.settings.items():
|
||||
cls._restore[k] = getattr(pdb_settings, k)
|
||||
setattr(pdb_settings, k, v)
|
||||
|
||||
@classmethod
|
||||
def tearDown(cls):
|
||||
for k,v in cls._restore.items():
|
||||
setattr(pdb_settings, k, v)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user