Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
58cc30e
definitions for OGC API DGGS + secure-data-proxy extensions
fmigneault Sep 8, 2025
d6bebbd
update changes and readme for secure-data-proxy
fmigneault Sep 8, 2025
f1fa541
add dggs component docs
fmigneault Sep 8, 2025
8569ae6
fix dggs references
fmigneault Sep 9, 2025
6d6340a
fix dggs nginx conf ignore + fix DGGS_DATA_DIR delayed eval
fmigneault Sep 9, 2025
0c480bd
patch DGGS/Tiles/docs endpoints with redirects
fmigneault Sep 10, 2025
e780052
update changelogs
fmigneault Sep 10, 2025
2a362f7
fix dggs api container registry reference
fmigneault Sep 10, 2025
5518c65
fix image ref
fmigneault Sep 10, 2025
5db42db
patch dggs docker image URI again
fmigneault Sep 10, 2025
9ceb96f
improve definitions and detail for secure-data-proxy
fmigneault Sep 10, 2025
7d93fec
update dggs api redirects strategy to result in correct links reporti…
fmigneault Sep 11, 2025
7547ea9
[ci-skip] update documentation of dggs volumes
fmigneault Sep 11, 2025
d959559
[skip-ci] add comments details
fmigneault Sep 12, 2025
3b81a3c
fix invalid H3->h3 casing for DGGS sample data source
fmigneault Sep 17, 2025
30d311e
update 'DATA_PROXY_ROOT -> BIRDHOUSE_DATA_PERSIST_ROOT in secure-data…
fmigneault Oct 2, 2025
4a64620
refine DGGS 307/308 redirects
fmigneault Oct 2, 2025
a39f974
add implementation warning comment about DGGS API and FastAPI ROOT_PA…
fmigneault Oct 2, 2025
6e46cba
realign dggs api versions with upstream
fmigneault Oct 7, 2025
7cafbbe
Merge branch 'master' into ogc-api-dggs
fmigneault Oct 7, 2025
f7a28d0
update default /data/dggs mount point to allow other /data usage with…
fmigneault Oct 8, 2025
a8ce6e7
move dggs sample to optional-component
fmigneault Oct 16, 2025
6423dd4
Merge remote-tracking branch 'origin/ogc-api-dggs' into ogc-api-dggs
fmigneault Oct 16, 2025
f2162ea
add magpie auth confic for public DGGS OpenAPI endpoints
fmigneault Oct 16, 2025
416be15
fix-tests
mishaschwartz Nov 11, 2025
2d591c3
fix tests for dggs (#603)
fmigneault Nov 11, 2025
5c06f21
Merge remote-tracking branch 'origin/master' into ogc-api-dggs
fmigneault Nov 24, 2025
4b943cc
update DGGS API to latest CRIM dev version
fmigneault Nov 24, 2025
d5434c9
add BIRDHOUSE_PROXY_CORS_ALLOW_ORIGIN setting (fixes #610)
fmigneault Nov 27, 2025
cba110c
add BIRDHOUSE_PROXY_CORS_ALLOW_ORIGIN setting (fixes #610)
fmigneault Nov 27, 2025
1c6ef7b
Merge branch 'add-cors-origin' into ogc-api-dggs
fmigneault Nov 27, 2025
85e13f4
document 'BIRDHOUSE_PROXY_CORS_ALLOW_ORIGIN' in env.local.example
fmigneault Nov 28, 2025
a96ce18
move '$access_control_allow_origin' to server level to allow localtio…
fmigneault Dec 1, 2025
d92d5ad
remove duplicate BIRDHOUSE_SSL_CERTIFICATE in env.local.example
fmigneault Dec 1, 2025
bf2900e
Merge branch 'add-cors-origin' into ogc-api-dggs
fmigneault Dec 1, 2025
65d4c72
Merge branch 'master' into add-cors-origin
fmigneault Dec 1, 2025
9aa8238
undo cors.include.template since not required anymore
fmigneault Dec 1, 2025
ec342f1
Merge branch 'add-cors-origin' of github-perso:bird-house/birdhouse-d…
fmigneault Dec 1, 2025
b805820
update changelog
fmigneault Dec 1, 2025
967c233
Merge branch 'add-cors-origin' into ogc-api-dggs
fmigneault Dec 1, 2025
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
18 changes: 17 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,23 @@
[Unreleased](https://github.com/bird-house/birdhouse-deploy/tree/master) (latest)
------------------------------------------------------------------------------------------------------------------

[//]: # (list changes here, using '-' for each new entry, remove this when items are added)
## Changes

- DGGS: Add the new `components/dggs` providing an OGC API for Discrete Global Grid Systems.
- DGGS API available through `/dggs-api` path (default, configurable via `DGGS_API_PATH`).
- Redirects available for `/ogcapi/dggs/...` and `/ogcapi/collections/.../dggs/...`.
- Sample configuration (minimum 1 resolvable data provider required) uses the new
feature of `optional-components/secure-data-proxy` on CRIM's Hirondelle server.

- Data: Allow `optional-components/secure-data-proxy` to define generic and flexible locations.
Copy link
Collaborator

@mishaschwartz mishaschwartz Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this since it makes it easy to mount any arbitrary location to proxy with an environment variable (that is prone to character escape issues, typos, etc.).

I think the better solution is to stick with what we had before where other components can create their own proxy path definitions and include SECURE_DATA_PROXY_AUTH_INCLUDE where needed. If you need a quick new secure path for something else it's easy to make a minimal optional-component.

Another option is to make this less error prone by allowing the user to define a path and a location on disk. Then we can mount the location on disk as a volume and serve it securely at the given path. This makes the whole thing less error-prone because the user is just defining two variables, not a whole location block.

That being said, I won't stop this PR just because I don't like this feature. I just think it may cause issues later on and I probably won't use it directly myself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel the escaping issue as that problematic.

I have defined it as followed on my end for the DGGS sample config, and it works without problem.
Since only basic redirects for data access aliases are expected, they shouldn't ever be much more complicated than that.

export SECURE_DATA_PROXY_LOCATIONS='
   location /data/samples/ {
     ${SECURE_DATA_PROXY_AUTH_INCLUDE}
     alias /data/secure-data-proxy/samples/;
   }
'

There are some much more scarier variables used elsewhere that do much more impactful/dangerous operations 😅

#c.DockerSpawner.allowed_images = {
# os.environ['JUPYTERHUB_IMAGE_SELECTION_NAMES'].split()[0]: os.environ['JUPYTERHUB_DOCKER_NOTEBOOK_IMAGES'].split()[0],
# os.environ['JUPYTERHUB_IMAGE_SELECTION_NAMES'].split()[1]: os.environ['JUPYTERHUB_DOCKER_NOTEBOOK_IMAGES'].split()[1],
# os.environ['JUPYTERHUB_IMAGE_SELECTION_NAMES'].split()[2]: os.environ['JUPYTERHUB_DOCKER_NOTEBOOK_IMAGES'].split()[2],
# os.environ['JUPYTERHUB_IMAGE_SELECTION_NAMES'].split()[3]: os.environ['JUPYTERHUB_DOCKER_NOTEBOOK_IMAGES'].split()[3],
# 'jupyter/scipy-notebook': 'jupyter/scipy-notebook',
# 'jupyter/r-notebook': 'jupyter/r-notebook',
# 'jupyter/tensorflow-notebook': 'jupyter/tensorflow-notebook',
# 'jupyter/datascience-notebook': 'jupyter/datascience-notebook',
# 'jupyter/pyspark-notebook': 'jupyter/pyspark-notebook',
# 'jupyter/all-spark-notebook': 'jupyter/all-spark-notebook',
#}
#"

# Allow for adding new config or override existing config in
# config/jupyterhub/jupyterhub_config.py.template.
#
#export JUPYTERHUB_CONFIG_OVERRIDE="
#
# Sample below will allow for sharing notebooks between Jupyter users.
# Note all shares are public.
#
### public-read paths
#
## /data/jupyterhub_user_data/public-share/
#public_read_on_disk = join(jupyterhub_data_dir, 'public-share')
#
## /notebook_dir/public-share/
#public_read_in_container = join(notebook_dir, 'public-share')
#
#c.DockerSpawner.volumes[public_read_on_disk] = {
# 'bind': public_read_in_container,
# 'mode': 'ro',
#}
#
### public-share paths
#
## /data/jupyterhub_user_data/public-share/{username}-public
#public_share_on_disk = join(public_read_on_disk, '{username}-public')
#
## /notebook_dir/mypublic-share
#public_share_in_container = join(notebook_dir, 'mypublic-share')
#
#c.DockerSpawner.volumes[public_share_on_disk] = {
# 'bind': public_share_in_container,
# 'mode': 'rw',
#}
#
## If enabling the public-share paths above, make sure that the paths in the container don't conflict
## with the PUBLIC_WORKSPACE_WPS_OUTPUTS_SUBDIR path.
#
### create dir with proper permissions
#
#def custom_create_dir_hook(spawner):
# username = spawner.user.name
#
# perso_public_share_dir = public_share_on_disk.format(username=username)
#
# for dir_to_create in [public_read_on_disk, perso_public_share_dir]:
# if not os.path.exists(dir_to_create):
# os.mkdir(dir_to_create, 0o755)
#
# subprocess.call(['chown', '-R', '1000:1000', public_read_on_disk])
#
# # call original create_dir_hook() function
# create_dir_hook(spawner)
#
#c.Spawner.pre_spawn_hook = custom_create_dir_hook
#"

#export THREDDS_ADDITIONAL_CATALOG='
# <datasetScan name="dataset_location_name" ID="dataset_url_path" path="dataset_url_path" location="dataset_location_on_container">
#
# <metadata inherited="true">
# <serviceName>all</serviceName>
# </metadata>
#
# <filter>
# <include wildcard="*.nc" />
# <include wildcard="*.ncml" />
# <include wildcard="*.txt" />
# <include wildcard="*.md" />
# <include wildcard="*.rst" />
# <include wildcard="*.csv" />
# </filter>
#
# </datasetScan>
#'
# It is possible to define additional compound services in the THREDDS_ADDITIONAL_CATALOG variable as well.
# This may be useful if you are creating a catalog that only provides a subset of the services defined in the
# compound service named "all" (see birdhouse/components/thredds/catalog.xml.template).
# DO NOT define any non-compound services in THREDDS_ADDITIONAL_CATALOG that is not an exact copy of one of the
# variables defined in "all"! Especially, do not change the "base" attribute of any existing service.
# Doing so may break the way that access permissions are enforced when accessing data through this service.
# Additional file filters to add for the Service Data THREDDS dataset. By default, the Service Data dataset will only
# serve files with the following extensions: .nc .ncml .txt .md .rst .csv
# If you need this dataset to serve other files you should update the THREDDS_SERVICE_DATA_EXTRA_FILE_FILTERS to add
# additional file filters.
# This may be useful to set if a WPS outputs files to the wps_outputs/ directory (hosted under the Service Data dataset)
# in a file format other than one of the defaults.
# See the example below which would also enable serving .png and .h5 files.
#export THREDDS_SERVICE_DATA_EXTRA_FILE_FILTERS="
# <include wildcard="*.png" />
# <include wildcard="*.h5" />
#"
# Set this variable to customize the body of the <datasetScan> XML element for the main THREDDS dataset. This is typically
# the dataset where you would store most of the data served by THREDDS (additional datasets can be configured by setting the
# THREDDS_ADDITIONAL_CATALOG variable).
# By default, the main dataset will only serve files with the following extensions: .nc .ncml .txt .md .rst .csv and will use
# the THREDDS service named "all" (see components/thredds/catalog.xml.template). However this can be customized if desired.
# See the example below which would change the configuration to serve .h5, .md, and .json files.
# See the THREDDS documentation for the <datasetScan> element for all configuration options.
#export THREDDS_DATASET_DATASETSCAN_BODY="
# <metadata inherited='true'>
# <serviceName>all</serviceName>
# </metadata>
#
# <filter>
# <include wildcard='*.h5' />
# <include wildcard='*.json' />
# <exclude wildcard='*.md' />
# </filter>
#"


Another option is to make this less error prone by allowing the user to define a path and a location on disk.

This could also possible, hence the introduction of SECURE_DATA_PROXY_ROOT as well.
I have actually considered providing a SECURE_DATA_PROXY_PATH for the location.

The only problem with this approach is that we end up needing a new location variable for every possible endpoint the user might want to employ to redirect data access in case they don't want all data to be served from the same URI.
This would be limiting the functionality, since it is not actually required to host all data from the same place (secure-data-proxy is reusable on purpose), such as leveraged by STAC:

location ${STAC_DATA_PROXY_URL_PATH}/ {
${SECURE_DATA_PROXY_AUTH_INCLUDE}
alias /stac-data-proxy/;
}

In that specific case, since stac component is involved, I could dedicate a specific variable, but I couldn't find a nicer (or less convoluted) way to offer an "<any>_SECURE_DATA_PROXY_PATH", so I opted for the approach to "just provide the location definition directly" instead.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I totally agree that we're doing some sketchy stuff with environment variables elsewhere and I'd love to figure out a better way for those cases as well. I just didn't want to contribute to the problem with a new variable as well.

I understand that this is simpler to implement and makes things extra flexible. I just worry that a node admin can easily get themselves in trouble by putting random stuff in this variable that breaks other things.

Copy link
Collaborator

@tlvu tlvu Oct 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I also find our use of config var to extend configuration file via template expansion of the config var very problematic:

  • escaping problems
  • duplicate problem if both component and env.local use the var, then env.local will have to append which result in duplicate config because env.local is read twice during read_configs.

Totally agree we should not perpetuate that same problematic pattern for newly added vars, my original feedback here #583 (comment) and here #583 (comment)

- `SECURE_DATA_PROXY_ROOT` can be defined as mount directory inside the `proxy` service.
- `SECURE_DATA_PROXY_LOCATIONS` can be defined with any amount of custom locations.
- All locations can be configured (as desired) under Magpie `secure-data-proxy` service for access control.
- Other components (`wps_output-volume`, `stac-data-proxy`) that can optionally use this security middleware
via `SECURE_DATA_PROXY_AUTH_INCLUDE` can still do so. Their mount points are handled separately.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does using SECURE_DATA_PROXY_AUTH_INCLUDE var means component secure-data-proxy must be enabled? Should mention it clearly, otherwise it does work and users won't know why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the other way around. By enabling secure-data-proxy, SECURE_DATA_PROXY_AUTH_INCLUDE gets defined with the nginx definition containing the pre-request to perform auth checks. All nginx configs that used the variable inherit that authentication check. If not enabled, it uses the fact that SECURE_DATA_PROXY_AUTH_INCLUDE is undefined, so the nginx config does not contain the auth request, making the data access essentially public.

secure-data-proxy applies in addition to file access, similar (or rather inversely) to some optional components that include extra Magpie public access rules to certain endpoints to open them.


- Weaver: Modified `/ogcapi/...` redirections strategy via `WEAVER_ALT_PREFIX_PROXY_LOCATION`.
- Allows other OGC APIs to reuse the same prefix to provide a unified location to access them.

[2.18.11](https://github.com/bird-house/birdhouse-deploy/tree/2.18.11) (2025-11-13)
------------------------------------------------------------------------------------------------------------------
Expand Down
50 changes: 45 additions & 5 deletions birdhouse/components/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -720,14 +720,12 @@ How to Enable the Component
- Edit ``env.local`` (a copy of `env.local.example`_)
- Add ``./components/stac`` to ``BIRDHOUSE_EXTRA_CONF_DIRS``.


STAC Browser
============

STAC Browser is a web UI used to interact with the STAC API.

Usage
-----

The STAC API can be browsed via the ``stac-browser`` component. By default, the browser will point to the STAC API
exposed by the current ``components/stac`` service.
Once this component is enabled, the STAC browser will be available at the ``https://<BIRDHOUSE_FQDN_PUBLIC>/stac-browser``
Expand All @@ -748,12 +746,53 @@ For example:
# you can update it to
export STAC_CORS_ORIGINS='http://example.com ~http:(www|other)\.api\.example\.com https://geojson.io'


How to Enable the Component
---------------------------

- Edit ``env.local`` (a copy of `env.local.example`_)
- Add ``./components/stac-browser`` to ``BIRDHOUSE_EXTRA_CONF_DIRS``.


.. _components_dggs:

DGGS: Discrete Global Grid Systems API
======================================

`DGGS`_ is a spatial reference system combining a discrete global grid hierarchy with a zone identifier, in contrast
to typical ``(lat, lon)`` spatial reference systems. By using a predefined and deterministic order of zone IDs and
refinement sub-zones, DGGS enables efficient access, representation and analysis of spatial data that has been
quantized over a certain grid reference system (DGGRS).

The *OGC API - DGGS* definition implemented by this service is a RESTful API that provides access to DGGS resources,
definitions, zonal query conversion, and data retrieval from precomputed datasets.

.. _DGGS: https://ogcapi.ogc.org/dggs/

Usage
-----

Once enabled, the API will be accessible (by default) on the ``/dggs-api`` endpoint.
It will also be available through the common ``/ogcapi/dggs`` alias.

Refer to the `DGGS`_ OGC API documentation for specific endpoints and features.

Refer to `vgrid DGGS <https://github.com/opengeoshub#vgrid-dggs>`_ and
the `vgrid repository <https://github.com/opengeoshub/vgrid>`_ for a relatively extensive
collection of DGGS tools and its associated data manipulation ecosystem (using ``xarray``, QGIS plugin, etc.).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also describe how to put the data you want to serve with this component in the right location so that it works as intended.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way to provide the data is actually dependent on the collection_provider definitions in pydggsapi-config.json. It does not necessarily need any local data if the provider uses a remote file or a DB connection.

I just so happened to have used the "local parquet file" approach for convenience of my sample data. Should I describe it even though it is only specific to that provider variant?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a simple example would be good so people can get started and then a reference to the relevant part of the documentation where they can customize their setup further if they want.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below for my suggestion about keeping the example data in a separate component.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not seen any example data added?

But personally I think just a documentation here is good enough. That part about "The way to provide the data is actually dependent on the collection_provider definitions in pydggsapi-config.json. It does not necessarily need any local data if the provider uses a remote file or a DB connection. I just so happened to have used the "local parquet file" approach for convenience of my sample data." is useful to add as documentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not seen any example data added?

Indeed. The current setup gets away with using the external file:
https://hirondelle.crim.ca/data/samples/dggs/H3/L7/2025-08-31/rl/RCM2_OK3556292_PK3777138_2_SC30MCPD_20250831_123917_RL.parquet

I like the alternate approach of optional component to keep things closer to the code.
I'll use that approach. The component will require that you employ it, or explicitly provide your own config.

How to Enable the Component
---------------------------

- Edit ``env.local`` (a copy of `env.local.example`_)
- Add ``./components/dggs`` to ``BIRDHOUSE_EXTRA_CONF_DIRS``.
- Define ``DGGS_CONFIG_PATH`` in the ``env.local`` with custom definitions.
Alternatively, employ sample DGGS dataset and configuration by enabling ``./optional-components/dggs-data-sample``.
Enabling this optional component will set ``DGGS_CONFIG_PATH`` with a predefined configuration for this sample data.
See the `PyDGGS-API implementation <https://github.com/LandscapeGeoinformatics/pydggsapi>`_ for more details.
- Optionally, configure variables in ``./components/dggs/default.env`` via ``env.local`` to customize the service.


Canarie-API
===========

Expand Down Expand Up @@ -986,10 +1025,11 @@ of all processes executed by these services.
Usage
-----

All outputs from these processes will become available at the ``${BIRDHOUSE_PROXY_SCHEME}://${BIRDHOUSE_FQDN_PUBLIC}/wpsoutputs`` endpoint.
All outputs from these processes will become available at
the ``${BIRDHOUSE_PROXY_SCHEME}://${BIRDHOUSE_FQDN_PUBLIC}/wpsoutputs`` endpoint.

By default, this endpoint is not protected. To secure access to this endpoint it is highly recommended to enable the
`./optional-components/secure-data-proxy` component as well.
``./optional-components/secure-data-proxy`` component as well.

How to Enable the Component
---------------------------
Expand Down
3 changes: 3 additions & 0 deletions birdhouse/components/dggs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
config/magpie/config.yml
config/proxy/conf.extra-service.d/dggs.conf
service-config.json
91 changes: 91 additions & 0 deletions birdhouse/components/dggs/config/magpie/config.yml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
providers:
# definition of STAC service for API access
${DGGS_API_NAME}:
url: http://dggs:8000
title: Discrete Global Grid System (DGGS) Service
public: true
c4i: false
type: api
sync_type: api

${DGGS_TILES_NAME}:
url: http://dggs:8000
title: Tiles support over Discrete Global Grid System (DGGS) Service
public: true
c4i: false
type: api
sync_type: api


permissions:
- service: ${DGGS_API_NAME}
resource: /openapi.json
permission: read
group: anonymous
action: create
- service: ${DGGS_API_NAME}
resource: ${DGGS_DOCS_PATH_INTERNAL}
permission: read
group: anonymous
action: create
- service: ${DGGS_API_NAME}
resource: /docs
permission: read
group: anonymous
action: create
- service: ${DGGS_API_NAME}
resource: /api
permission: read
group: anonymous
action: create

# === DGGS API ===
# /${DGGS_API_NAME}/dggs/...
# /${DGGS_API_NAME}/collections/{collectionId}/dggs/...

# Administrator permissions over whole service
- service: ${DGGS_API_NAME}
permission: read
group: administrators
action: create
- service: ${DGGS_API_NAME}
permission: write
group: administrators
action: create
# Open access to the entrypoint
- service: ${DGGS_API_NAME}
permission: read-match
group: anonymous
action: create
# Open access to the generic DGGRS definitions
# DGGS-nested endpoints and Collections access managed by user/groups.
- service: ${DGGS_API_NAME}
resource: /dggs
permission: read-match
group: anonymous
action: create
# Open access to the documentation endpoints
- service: ${DGGS_API_NAME}
resource: /conformance
permission: read-match
group: anonymous
action: create

# === Tiles API ===
# /${DGGS_TILES_NAME}/{collectionId}.json
# /${DGGS_TILES_NAME}/{collectionId}/{z}/{x}/{x}

# Administrator permissions over whole service
- service: ${DGGS_TILES_NAME}
permission: read
group: administrators
action: create
- service: ${DGGS_TILES_NAME}
permission: write
group: administrators
action: create
# Tiles-only endpoint. Collections access managed by user/groups.
- service: ${DGGS_TILES_NAME}
permission: read-match
group: anonymous
action: create
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

services:
magpie:
volumes:
- ./components/dggs/config/magpie/config.yml:${MAGPIE_PROVIDERS_CONFIG_PATH}/dggs.yml:ro
- ./components/dggs/config/magpie/config.yml:${MAGPIE_PERMISSIONS_CONFIG_PATH}/dggs.yml:ro
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@

location = /dggs-auth {
internal;
# note: using 'TWITCHER_VERIFY_PATH' path to avoid performing the request via proxy 'TWITCHER_PROTECTED_PATH'
# This ensures that access is validated for the user, but does not trigger its access/download twice.
# It is also more efficient, since less contents are transferred/buffered.
proxy_pass ${BIRDHOUSE_PROXY_SCHEME}://${BIRDHOUSE_FQDN_PUBLIC}${TWITCHER_VERIFY_PATH}/$request_uri;
proxy_pass_request_body off;
proxy_set_header Host $host;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-Proto $real_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host:$server_port;
}

# Generic API docs
location ${DGGS_API_PATH}/docs {
auth_request /dggs-auth;
auth_request_set $auth_status $upstream_status;

proxy_pass http://dggs:8000${DGGS_DOCS_PATH_INTERNAL}/$is_args$args;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These will skip authentication since location blocks with plain strings are matched before those with regular expressions.

Since you're only authenticating with the ^${DGGS_API_PATH}/(.*)$ pattern these will all not be authenticated by magpie/twitcher.

Copy link
Member Author

@fmigneault fmigneault Oct 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.
These documentation endpoints are made public by default in Magpie config, hence why I didn't bother causing unnecessary auth pre-requests.

Should I add the same auth_request /dggs-auth; as the other endpoint if desired just for completion, even though redundant?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just because they're made public by default doesn't mean that that setting can't be manually changed later by another optional component or directly through the Magpie UI/API.

So yes please, add the same auth_request lines here and everywhere so that it will support non-default settings.

proxy_set_header Host $host;
#proxy_set_header X-Original-URI $request_uri;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $real_scheme;
proxy_set_header X-Forwarded-Host $http_host:$server_port;
#proxy_set_header X-Script-Name ${DGGS_API_PATH};
}
location ${DGGS_TILES_PATH}/docs {
auth_request /dggs-auth;
auth_request_set $auth_status $upstream_status;

proxy_pass http://dggs:8000${DGGS_DOCS_PATH_INTERNAL}/$is_args$args;
proxy_set_header Host $host;
#proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $real_scheme;
proxy_set_header X-Forwarded-Host $http_host:$server_port;
#proxy_set_header X-Script-Name ${DGGS_API_PATH};
}
# '/api' is the standard path by OGC: https://ogcapi.ogc.org/common/overview.html
location = ${DGGS_API_PATH}/api {
auth_request /dggs-auth;
auth_request_set $auth_status $upstream_status;

rewrite ^${DGGS_API_PATH}/(.*) ${DGGS_API_PATH_INTERNAL}/$1 break;
proxy_pass http://dggs:8000;
proxy_set_header Host $host;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $real_scheme;
proxy_set_header X-Forwarded-Host $http_host:$server_port;
#proxy_set_header X-Script-Name ${DGGS_API_PATH};
}

# DGGS API
location = ${DGGS_API_PATH} {
return 308 ${DGGS_API_PATH}/$is_args$args;
}
location ~ ^${DGGS_API_PATH}/(.*)$ {
auth_request /dggs-auth;
auth_request_set $auth_status $upstream_status;

proxy_pass http://dggs:8000${DGGS_API_PATH_INTERNAL}/$1$is_args$args;
proxy_set_header Host $host;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $real_scheme;
proxy_set_header X-Forwarded-Host $http_host:$server_port;
}
# Tiles API
location = ${DGGS_TILES_PATH} {
return 308 ${DGGS_TILES_PATH}/$is_args$args;
}
location ~ ^${DGGS_TILES_PATH}/(.*)$ {
auth_request /dggs-auth;
auth_request_set $auth_status $upstream_status;

proxy_pass http://dggs:8000${DGGS_TILES_PATH_INTERNAL}/$1$is_args$args;
proxy_set_header Host $host;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $real_scheme;
proxy_set_header X-Forwarded-Host $http_host:$server_port;
}

# NOTE:
# Redirect to internal network of Twitcher with root endpoint and alias allows to set
# the same 'magpie' permissions on the 'dggs' service.
# This allows verification of the same service user/group permissions references regardless
# whether the *shortcut* endpoint, the alias or the explicit 'twitcher' proxy route is used.
location = ${TWITCHER_PROTECTED_PATH}${DGGS_API_PATH} {
return 308 ${DGGS_API_PATH}/$is_args$args;
}
location ~ ^${TWITCHER_PROTECTED_PATH}${DGGS_API_PATH}/(.*)$ {
return 308 ${DGGS_API_PATH}/$1$is_args$args;
}
location = ${TWITCHER_PROTECTED_PATH}${DGGS_TILES_PATH} {
return 308 ${DGGS_TILES_PATH}/$is_args$args;
}
location ~ ^${TWITCHER_PROTECTED_PATH}${DGGS_TILES_PATH}/(.*)$ {
return 308 ${DGGS_TILES_PATH}/$1$is_args$args;
}

# NOTE:
# Redirect to typical endpoints employed by clients.
# Use 307 instead of 308 as above to indicate and hint clients that this is only a
# shortcut to be revalidatd rather than the definitive location of the actual service.
# The 'collection' variant is explicitly listed since '/ogcapi/' prefix could be
# used for other services (e.g.: '/ogcapi/processes' for Weaver).
location ~ ^/ogcapi/dggs(.*)$ {
return 307 ${DGGS_API_PATH}$1$is_args$args;
}
location ~ ^/ogcapi/collections/(.*)/dggs(.*)$ {
return 307 ${DGGS_API_PATH}/collections/$1/dggs$2$is_args$args;
}
location ~ ^/ogcapi/tiles(.*)$ {
return 307 ${DGGS_TILES_PATH}$1$is_args$args;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
proxy:
volumes:
- ./components/dggs/config/proxy/conf.extra-service.d:/etc/nginx/conf.extra-service.d/dggs:ro
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

services:
# extend twitcher with MagpieAdapter hooks employed for DGGS proxied requests
twitcher:
volumes:
# NOTE: MagpieAdapter hooks are defined within Magpie config, but it is actually Twitcher proxy that runs them
# target mount location depends on 'MAGPIE_PROVIDERS_CONFIG_PATH' environment variable that is found under `birdhouse/components/twitcher/docker-compose-extra.yml`
- ./components/dggs/config/magpie/config.yml:/opt/birdhouse/src/magpie/config/dggs-config.yml:ro
Loading
Loading