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 0deb482 commit 36f40df
Show file tree
Hide file tree
Showing 9 changed files with 1,507 additions and 39 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
[![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`, an API key will be checked and required for
these layers

## 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 36f40df

Please sign in to comment.