Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes for IP validation #3542

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def safe_key() -> str:
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"metadeploy.multitenancy.middleware.CurrentSiteMiddleware",
"metadeploy.multitenancy.iprestrict_middleware.IPRestrictMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
Expand Down
1 change: 1 addition & 0 deletions metadeploy/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@ class SiteProfile(TranslatableModel):
show_metadeploy_wordmark = models.BooleanField(default=True)
company_logo = models.ImageField(blank=True)
favicon = models.ImageField(blank=True)
allowed_ip_addresses = models.JSONField(default=list, blank=True, null=True)

@property
def welcome_text_markdown(self):
Expand Down
1 change: 1 addition & 0 deletions metadeploy/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ class Meta:
"show_metadeploy_wordmark",
"company_logo",
"favicon",
"allowed_ip_addresses",
)


Expand Down
22 changes: 22 additions & 0 deletions metadeploy/multitenancy/iprestrict_middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from metadeploy.api.models import SiteProfile
from . import current_site_id
from django.http import HttpResponseForbidden

class IPRestrictMiddleware:
def getSiteProfile(self):
profile = SiteProfile.objects.filter(site=current_site_id()).first()
return profile

def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
client_ip = request.META.get('REMOTE_ADDR', None)
profile = self.getSiteProfile()

if hasattr(profile, "allowed_ip_addresses") and profile.allowed_ip_addresses:
if client_ip not in profile.allowed_ip_addresses:
return HttpResponseForbidden("You don't have permission to access this resource.")

response = self.get_response(request)
return response
70 changes: 70 additions & 0 deletions metadeploy/multitenancy/tests/test_iprestrict_middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from metadeploy.multitenancy.iprestrict_middleware import IPRestrictMiddleware
from django.contrib.sites.models import Site
from metadeploy.api.models import SiteProfile
from django.test import RequestFactory, TestCase
from unittest.mock import patch


class IPRestrictionMiddlewaretest(TestCase):
def setUp(self):
self.factory = RequestFactory()

@patch('metadeploy.multitenancy.iprestrict_middleware.IPRestrictMiddleware.getSiteProfile')
def test_ip_restrict_middleware_with_matching_allowed_client_ip(self, mock_site_profile_get):
request = self.factory.get('/test')
request.META["REMOTE_ADDR"] = "127.0.0.1"

site = Site.objects.create(name="Test")
mock_site_profile = SiteProfile()
mock_site_profile.site = site
mock_site_profile.name = site.name
mock_site_profile.allowed_ip_addresses = '["127.0.0.1"]'
mock_site_profile_get.return_value = mock_site_profile

response = IPRestrictMiddleware(lambda x: x)(request)
assert response == request


@patch('metadeploy.multitenancy.iprestrict_middleware.IPRestrictMiddleware.getSiteProfile')
def test_ip_restrict_middleware_without_matching_allowed_client_ip(self, mock_site_profile_get):
request = self.factory.get('/test')
request.META["REMOTE_ADDR"] = "127.0.0.2"

site = Site.objects.create(name="Test")
mock_site_profile = SiteProfile()
mock_site_profile.site = site
mock_site_profile.name = site.name
mock_site_profile.allowed_ip_addresses = '["127.0.0.1"]'
mock_site_profile_get.return_value = mock_site_profile

response = IPRestrictMiddleware(lambda x: x)(request)
assert response.status_code == 403

@patch('metadeploy.multitenancy.iprestrict_middleware.IPRestrictMiddleware.getSiteProfile')
def test_ip_restrict_middleware_without_allowed_list(self, mock_site_profile_get):
request = self.factory.get('/test')
request.META["REMOTE_ADDR"] = "127.0.0.1"

site = Site.objects.create(name="Test")
mock_site_profile = SiteProfile()
mock_site_profile.site = site
mock_site_profile.name = site.name
mock_site_profile_get.return_value = mock_site_profile

response = IPRestrictMiddleware(lambda x: x)(request)
assert response == request

@patch('metadeploy.multitenancy.iprestrict_middleware.IPRestrictMiddleware.getSiteProfile')
def test_ip_restrict_middleware_with_allowed_list_none(self, mock_site_profile_get):
request = self.factory.get('/test')
request.META["REMOTE_ADDR"] = "127.0.0.1"

site = Site.objects.create(name="Test")
mock_site_profile = SiteProfile()
mock_site_profile.site = site
mock_site_profile.name = site.name
mock_site_profile.allowed_ip_addresses = None
mock_site_profile_get.return_value = mock_site_profile

response = IPRestrictMiddleware(lambda x: x)(request)
assert response == request