Skip to content

Commit

Permalink
Allow proxying links connected to remote resources
Browse files Browse the repository at this point in the history
  • Loading branch information
giohappy committed Aug 6, 2024
1 parent c7232fc commit 3676baf
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 47 deletions.
59 changes: 17 additions & 42 deletions geonode/proxy/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def setUp(self):
super().setUp()
self.maxDiff = None
self.admin = get_user_model().objects.get(username="admin")
create_models(type="dataset")

# FIXME(Ariel): These tests do not work when the computer is offline.
self.proxy_url = "/proxy/"
Expand Down Expand Up @@ -101,58 +102,32 @@ def test_proxy_not_allowed_path(self):
self.assertEqual(response.status_code, 403, response.status_code)

@override_settings(PROXY_ALLOWED_PARAMS_NEEDLES=(), PROXY_ALLOWED_PATH_NEEDLES=())
@patch("geonode.proxy.views.proxy_urls_registry", ProxyUrlsRegistry().clear())
def test_validate_remote_services_hosts(self):
# @patch("geonode.proxy.views.proxy_urls_registry", ProxyUrlsRegistry().clear())
def test_validate_remote_links_hosts(self):
"""If PROXY_ALLOWED_HOSTS is empty and DEBUG is False requests should return 200
for Remote Services hosts."""
from geonode.services.models import Service
from geonode.services.enumerations import WMS, INDEXED

service, _ = Service.objects.get_or_create(
type=WMS,
name="Bogus",
title="Pocus",
owner=self.admin,
method=INDEXED,
base_url="http://bogus.pocus.com/ows",
from geonode.base.models import Link

dataset = Dataset.objects.all().first()
dataset.sourcetype = "REMOTE"
dataset.save()

link, _ = Link.objects.get_or_create(
link_type="OGC:WMS",
resource=dataset,
extension="html",
name="WMS",
mime="text/html",
url="http://bogus.pocus.com/ows",
)
response = self.client.get(f"{self.proxy_url}?url=http://bogus.pocus.com/ows")
self.assertNotEqual(response.status_code, 403, response.status_code)

# The service should be removed from the proxy registry
service.delete()
link.delete()
response = self.client.get(f"{self.proxy_url}?url=http://bogus.pocus.com/ows")
self.assertEqual(response.status_code, 403, response.status_code)

# Two services with the same hostname are added to the proxy registry
service, _ = Service.objects.get_or_create(
type=WMS,
name="Bogus",
title="Pocus",
owner=self.admin,
method=INDEXED,
base_url="http://bogus.pocus.com/ows",
)
Service.objects.get_or_create(
type=WMS,
name="Bogus2",
title="Pocus",
owner=self.admin,
method=INDEXED,
base_url="http://bogus.pocus.com/wms",
)
response = self.client.get(f"{self.proxy_url}?url=http://bogus.pocus.com/ows")
self.assertNotEqual(response.status_code, 403, response.status_code)
response = self.client.get(f"{self.proxy_url}?url=http://bogus.pocus.com/wms")
self.assertNotEqual(response.status_code, 403, response.status_code)

service.delete()
response = self.client.get(f"{self.proxy_url}?url=http://bogus.pocus.com/wfs")
# The request passes because the same hostname is still registered for the other serrice
self.assertNotEqual(response.status_code, 403, response.status_code)
response = self.client.get(f"{self.proxy_url}?url=http://bogus.pocus.com/wcs")
self.assertNotEqual(response.status_code, 403, response.status_code)

@patch("geonode.proxy.views.proxy_urls_registry", ProxyUrlsRegistry().set([".example.org"]))
def test_relative_urls(self):
"""Proxying to a URL with a relative path element should normalise the path into
Expand Down
36 changes: 31 additions & 5 deletions geonode/proxy/utils.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
from urllib.parse import urlsplit

from django.conf import settings
from django.db.models import signals


site_url = urlsplit(settings.SITEURL)

PROXIED_LINK_TYPES = ["OGC:WMS", "OGC:WFS", "data"]


class ProxyUrlsRegistry:
_first_init = True

def initialize(self):
from geonode.base.models import Link
from geonode.geoserver.helpers import ogc_server_settings
from geonode.services.models import Service

self.proxy_allowed_hosts = set([site_url.hostname] + list(getattr(settings, "PROXY_ALLOWED_HOSTS", ())))

if ogc_server_settings:
self.proxy_allowed_hosts.add(ogc_server_settings.hostname)
self.register_host(ogc_server_settings.hostname)

for _s in Service.objects.all():
_remote_host = urlsplit(_s.base_url).hostname
self.proxy_allowed_hosts.add(_remote_host)
for link in Link.objects.filter(resource__sourcetype="REMOTE", link_type__in=PROXIED_LINK_TYPES):
remote_host = urlsplit(link.url).hostname
self.register_host(remote_host)

if self._first_init:
signals.post_save.connect(link_post_save, sender=Link)
signals.post_delete.connect(link_post_delete, sender=Link)
self._first_init = False

def set(self, hosts):
self.proxy_allowed_hosts = set(hosts)
Expand All @@ -39,3 +49,19 @@ def get_proxy_allowed_hosts(self):


proxy_urls_registry = ProxyUrlsRegistry()


def link_post_save(instance, sender, **kwargs):
if (
instance.resource
and instance.resource.sourcetype == "REMOTE"
and instance.url
and instance.link_type in PROXIED_LINK_TYPES
):
remote_host = urlsplit(instance.url).hostname
proxy_urls_registry.register_host(remote_host)


def link_post_delete(instance, sender, **kwargs):
# We reinitialize the registry otherwise we might delete a host requested by another service with the same hostanme
proxy_urls_registry.initialize()

0 comments on commit 3676baf

Please sign in to comment.