Skip to content

Commit

Permalink
API key - check for Google or Bing layers without an API key
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustry committed Jun 3, 2024
1 parent 4a20e21 commit fbc352f
Show file tree
Hide file tree
Showing 9 changed files with 1,509 additions and 39 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
[![QGIS.org](https://img.shields.io/badge/QGIS.org-published-green)](https://plugins.qgis.org/plugins/lizmap_server/)
[![Tests 🎳](https://github.com/3liz/qgis-lizmap-server-plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/3liz/qgis-lizmap-server-plugin/actions/workflows/ci.yml)

## Environment variables

* `QGIS_SERVER_LIZMAP_REVEAL_SETTINGS`, read
[docs.lizmap.com documentation](https://docs.lizmap.com/current/en/install/pre_requirements.html#qgis-server-plugins)
* `STRICT_BING_TOS_CHECK` and `STRICT_GOOGLE_TOS_CHECK`, if set to `TRUE` (the default value), an API key will be
checked and required for these layers. If no API key provided in the Lizmap plugin, these layers will be discarded.
If set to `FALSE`, these layers will be forwarded from QGIS Server to Lizmap Web Client but these layers might not work
and the TOS from these providers might not be compliant.

## Download

### Stable
Expand Down
44 changes: 37 additions & 7 deletions lizmap_server/lizmap_accesscontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
)
from lizmap_server.logger import Logger, profiling
from lizmap_server.tools import to_bool
from lizmap_server.tos_definitions import (
BING_DOMAIN,
BING_KEY,
GOOGLE_DOMAIN,
GOOGLE_KEY,
strict_tos_check,
)


class LizmapAccessControlFilter(QgsAccessControlFilter):
Expand All @@ -30,6 +37,10 @@ def __init__(self, server_iface: QgsServerInterface) -> None:
super().__init__(server_iface)

self.iface = server_iface
self._strict_google = strict_tos_check(GOOGLE_KEY)
self._strict_bing = strict_tos_check(BING_KEY)

Logger.info(f"LayerAccessControl : Google {self._strict_google}, Bing {self._strict_bing}")

# def layerFilterExpression(self, layer: QgsVectorLayer) -> str:
# """ Return an additional expression filter """
Expand Down Expand Up @@ -77,8 +88,7 @@ def layerPermissions(self, layer: QgsMapLayer) -> QgsAccessControlFilter.LayerPe
# Discard invalid layers for other services than WMS
if not layer.isValid() and request_handler.parameter('service').upper() != 'WMS':
Logger.info(f"layerPermission: Layer {layer_name} is invalid in {project.fileName()}!")
rights.canRead = False
rights.canInsert = rights.canUpdate = rights.canDelete = False
rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = False
return rights

# Get Lizmap user groups provided by the request
Expand All @@ -94,20 +104,40 @@ def layerPermissions(self, layer: QgsMapLayer) -> QgsAccessControlFilter.LayerPe

# Try to override filter expression cache
is_wfs = request_handler.parameter('service').upper() == 'WFS'
if is_wfs and request_handler.parameter('request') == 'getfeature':
if is_wfs and request_handler.parameter('request').upper() == 'GETFEATURE':
self.iface.accessControls().resolveFilterFeatures([layer])

# If groups is empty, no Lizmap user groups provided by the request
# The default layer rights is applied
if len(groups) == 0:
return rights
datasource = layer.source().lower()
is_google = GOOGLE_DOMAIN in datasource
is_bing = BING_DOMAIN in datasource
if is_google or is_bing:
Logger.info(f"Layer '{layer_name}' has been detected as an external layer which might need a API key.")

# Get Lizmap config
cfg = get_lizmap_config(self.iface.configFilePath())
if not cfg:
if is_google:
rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = not self._strict_google
elif is_bing:
rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = not self._strict_bing
# Default layer rights applied
return rights

# If groups is empty, no Lizmap user groups provided by the request
# The default layer rights is applied
if len(groups) == 0 and not (is_google or is_bing):
return rights

api_key = cfg['options'].get('googleKey', '')
if is_google and not api_key and strict_tos_check(GOOGLE_KEY):
rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = False
return rights

api_key = cfg['options'].get('bingKey', '')
if is_bing and not api_key and strict_tos_check(BING_KEY):
rights.canRead = rights.canInsert = rights.canUpdate = rights.canDelete = False
return rights

# Get layers config
cfg_layers = get_lizmap_layers_config(cfg)
if not cfg_layers:
Expand Down
9 changes: 9 additions & 0 deletions lizmap_server/server_info_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

from lizmap_server.exception import ServiceError
from lizmap_server.tools import check_environment_variable, to_bool
from lizmap_server.tos_definitions import (
BING_KEY,
GOOGLE_KEY,
strict_tos_check,
)

try:
# Py-QGIS-Server
Expand Down Expand Up @@ -208,6 +213,10 @@ def handleRequest(self, context):
'commit_id': py_qgis_server_metadata.commit_id,
'stable': py_qgis_server_metadata.is_stable,
},
'external_providers_tos_checks': {
GOOGLE_KEY.lower(): strict_tos_check(GOOGLE_KEY),
BING_KEY.lower(): strict_tos_check(BING_KEY),
},
# 'support_custom_headers': self.support_custom_headers(),
'services': services_available,
'plugins': plugins,
Expand Down
26 changes: 26 additions & 0 deletions lizmap_server/tos_definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
__copyright__ = 'Copyright 2024, 3Liz'
__license__ = 'GPL version 3'
__email__ = '[email protected]'

import os

from lizmap_server.tools import to_bool

GOOGLE_KEY = 'GOOGLE'
BING_KEY = 'BING'

GOOGLE_DOMAIN = 'google.com'
BING_DOMAIN = 'virtualearth.net'


def strict_tos_check_key(provider: str) -> str:
""" Check the environment variable for this provider. """
return f'STRICT_{provider}_TOS_CHECK'


def strict_tos_check(provider: str) -> bool:
""" Check the environment variable for this provider. """
env = os.getenv(strict_tos_check_key(provider))
if env is None:
env = True
return to_bool(env)
Loading

0 comments on commit fbc352f

Please sign in to comment.