Skip to content

Commit e77d8a9

Browse files
authored
Merge pull request #634 from Ouranosinc/thredds-prefix-path-fix
2 parents 518e645 + 81f7208 commit e77d8a9

File tree

4 files changed

+36
-21
lines changed

4 files changed

+36
-21
lines changed

CHANGES.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Changes
99
`Unreleased <https://github.com/Ouranosinc/Magpie/tree/master>`_ (latest)
1010
------------------------------------------------------------------------------------
1111

12-
* Nothing new for the moment.
12+
* Allow ``metadata_type.prefixes`` and ``data_type.prefixes`` in ``ServiceTHREDDS`` configuration to contain ``/`` character.
1313

1414
.. _changes_4.1.1:
1515

@@ -563,7 +563,7 @@ Features / Changes
563563
`Ouranosinc/Magpie#473 <https://github.com/Ouranosinc/Magpie/pull/473>`_,
564564
see also
565565
`Avoid Accessing the Authentication Policy
566-
<https://docs.pylonsproject.org/projects/pyramid_tm/en/latest/#avoid-accessing-the-authentication-policy>`_).
566+
<https://docs.pylonsproject.org/projects/pyramid-tm/en/latest/#avoid-accessing-the-authentication-policy>`_).
567567

568568
.. _changes_3.17.1:
569569

docs/services.rst

+7
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ by the below configuration.
301301
- dap4
302302
- wcs
303303
- wms
304+
- ncss/grid
305+
- ncss/point
304306
305307
.. warning:: Regular Expression Patterns
306308

@@ -322,6 +324,11 @@ by the below configuration.
322324
API entrypoint and `Tomcat` service running it. If this feature is not needed, it can be disabled by setting the
323325
parameter to ``null``.
324326

327+
.. versionchanged:: 4.2.0
328+
``prefixes`` can now contain a ``/`` character. This allows `ServiceTHREDDS`_ to properly handle `THREDDS`_ services
329+
that have multiple path parts. For example, starting with `THREDDS`_ version 5, the ``ncss`` service contains two
330+
sub-services which are accessed using the path prefixes ``ncss/grid`` and ``ncss/point``.
331+
325332
Assuming a proxy intended to receive incoming requests configured with :class:`magpie.adapter.MagpieAdapter` such that
326333
``{PROXY_URL}`` is the base path, the following path would point toward the registered service with the above YAML
327334
configuration.

magpie/services.py

+22-16
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,21 @@ def get_path_parts(self):
13821382
return path_parts[1:] # remove extra '' added by split
13831383
return path_parts
13841384

1385+
def _get_path_prefix_permission(self, path_parts):
1386+
# type: (List[str]) -> Tuple[Optional[Str], PermissionRequested]
1387+
cfg = self.get_config()
1388+
# first to favor BROWSE over READ prefix conflicts
1389+
for prefixes, permission in ((cfg["metadata_type"]["prefixes"], Permission.BROWSE),
1390+
(cfg["data_type"]["prefixes"], Permission.READ)):
1391+
for pattern_prefix in prefixes:
1392+
if not path_parts and pattern_prefix is None:
1393+
return pattern_prefix, permission
1394+
if pattern_prefix is not None:
1395+
path_prefix = "/".join(path_parts[:pattern_prefix.count("/") + 1])
1396+
if self.is_match(path_prefix, pattern_prefix) is not None:
1397+
return path_prefix, permission
1398+
return None, None
1399+
13851400
@staticmethod
13861401
def is_match(value, pattern):
13871402
# type: (Str, Str) -> Optional[Str]
@@ -1396,11 +1411,14 @@ def is_match(value, pattern):
13961411
def resource_requested(self):
13971412
# type: () -> TargetResourceRequested
13981413
path_parts = self.get_path_parts()
1399-
1414+
path_prefix, _ = self._get_path_prefix_permission(path_parts)
14001415
# handle optional prefix as targeting the service directly
14011416
if not path_parts or len(path_parts) < 2:
14021417
return self.service, True
1403-
path_parts = path_parts[1:]
1418+
if path_prefix:
1419+
path_parts = path_parts[path_prefix.count("/") + 1:]
1420+
else:
1421+
path_parts = path_parts[1:]
14041422
cfg = self.get_config()
14051423

14061424
# find deepest possible resource matching either Directory or File by name
@@ -1431,21 +1449,9 @@ def resource_requested(self):
14311449

14321450
def permission_requested(self):
14331451
# type: () -> PermissionRequested
1434-
cfg = self.get_config()
14351452
path_parts = self.get_path_parts()
1436-
path_prefix = None # in case of no `<prefix>`, simulate as `null`
1437-
if path_parts:
1438-
path_prefix = path_parts[0]
1439-
for prefixes, permission in [
1440-
(cfg["metadata_type"]["prefixes"], Permission.BROWSE), # first to favor BROWSE over READ prefix conflicts
1441-
(cfg["data_type"]["prefixes"], Permission.READ),
1442-
]:
1443-
for pattern_prefix in prefixes: # type: Str
1444-
if path_prefix is None and pattern_prefix is None:
1445-
return permission
1446-
if self.is_match(path_prefix, pattern_prefix) is not None:
1447-
return permission
1448-
return None # automatically deny
1453+
_, permission = self._get_path_prefix_permission(path_parts)
1454+
return permission
14491455

14501456

14511457
class ServiceGeoserverWPS(ServiceGeoserverBase, ServiceWPS): # order important to call overridden class properties

tests/test_services.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ def test_ServiceTHREDDS_custom_config(self):
504504
# only allow these variants, other should be blocked ("dap4", "wcs", "wms")
505505
- dodsC
506506
- fileServer
507+
- ncss/grid
507508
metadata_type:
508509
prefixes:
509510
# only allow these variants, others should be blocked ("ncml", "uddc", "iso")
@@ -531,7 +532,7 @@ def test_ServiceTHREDDS_custom_config(self):
531532
utils.check_val_is_in("data_type", svc_config)
532533
utils.check_val_is_in("metadata_type", svc_config)
533534
utils.check_val_equal(svc_config["file_patterns"], [".*\\.ncml", ".*\\.nc"])
534-
utils.check_val_equal(svc_config["data_type"]["prefixes"], ["dodsC", "fileServer"])
535+
utils.check_val_equal(svc_config["data_type"]["prefixes"], ["dodsC", "fileServer", "ncss/grid"])
535536
utils.check_val_equal(svc_config["metadata_type"]["prefixes"], [None, "catalog"])
536537

537538
# create resources
@@ -565,7 +566,7 @@ def test_ServiceTHREDDS_custom_config(self):
565566
# (same resource because matching '.*.nc' regex, NCML file matched by other '.*.ncml' regex, so other Resource)
566567
# only accessible via specified data prefixes
567568
allowed_files = [file_name, file_html_name]
568-
known_prefixes = ["dodsC", "fileServer"]
569+
known_prefixes = ["dodsC", "fileServer", "ncss/grid"]
569570
for prefix in known_prefixes:
570571
for test_file in allowed_files:
571572
path = "/ows/proxy/{}/{}/{}/{}".format(svc_name, prefix, dir_name, test_file)
@@ -580,7 +581,8 @@ def test_ServiceTHREDDS_custom_config(self):
580581
utils.check_raises(lambda: self.ows.check_request(req), OWSAccessForbidden, msg=msg)
581582

582583
# using unknown prefixes, otherwise allowed file should always be denied
583-
unknown_prefixes = ["ncml", "dap4"] # purposely take normally allowed THREDDS prefixes, validate active config
584+
# purposely take normally allowed THREDDS prefixes, validate active config
585+
unknown_prefixes = ["ncml", "dap4", "ncss/point", "ncss", "grid"]
584586
allowed_resources = [dir_name, "{}/{}".format(dir_name, file_name), "{}/{}".format(dir_name, file_html_name)]
585587
for prefix in unknown_prefixes:
586588
for target in allowed_resources:

0 commit comments

Comments
 (0)