Accediendo a datos de QGIS Server con base en roles de usuario

Uno de los requerimientos más frecuentes para servicios web geográficos que disponen datos sensibles es: cómo restringir el acceso a los mismos dependiendo el rol del usuario. Este post muestra una manera de restringir el acceso a tus servicios web geográficos en QGIS Server.

Instalación de QGIS Server en Windows

Para correr QGIS Server sobre Windows debes instalar un servidor web como Apache o NGINX. Este post no abordará la instalación en detalle, si conoces de servidores web y puedes instalar uno, genial! Si no conoces, perso quieres seguir este post en tu propio equipo, tienes básicamente dos opciones:

1. Descargar OSGeo4W for 64 bits y seguir las instrucciones de QGIS docs, o,

2. Descargar OSGeo4W for 32 bits (si, lo leíste bien). La versión de 32 bits del instalador de OSGeo4W incluye Apache, lo cual está bien para este demo. Por supuesto, en ambiente de producción deberías usar paquetes para 64 bits.

Ten presente que este post está basado en rutas para la opción 2. Esto es, si eliges el instalador para 64 bits, debes tener cuidado con las rutas que involucran carpetas de OSGeo4W.

Si te decides por los paquetes para 32 bits, luego de descargar y ejecutar OSGeo4W para 32 bits, elige los siguientes 3 paquetes para la instalación: Apache 2, QGIS LTR and QGIS Server LTR. Una vez instalados, reinicia el sistema y ejecuta  ApacheMonitor.exe, ubicado en C:/OSGeo4W/apache/bin/ApacheMonitor.exe, el cual te permite controlar el estado del servidor Apache desde la barra de tareas.

(Ignora el mensaje de “Activar Windows”, es que nunca lo uso :P)

Publicando un servicio web geográfico

Para una introducción breve sobre cómo funciona QGIS Server y de lo que es capaz, podrías leer estas presentaciones: Introduction to QGIS Server and Taller de QGIS Server.

QGIS Server necesita un proyecto QGS/QGZ. Para un demo rápido puedes descargar un proyecto con sus respectivos datos desde este enlace.

Descarga el archivo ZIP y descomprímelo en C:/ de tal manera que puedas acceder a C:/qgis\\projects\\catastro.qgz y C:/qgis\\projects\\datos_catastro_taller_qgis_server.gpkg localmente.

Ahora que el proyecto de QGIS y sus datos están ubicados en esa carpeta específica (es una carpeta elegida para este demo, pero podrías usar otras rutas en tu servidor), puedes ir a la siguiente URL en tu navegador web:

http://localhost/qgis-ltr/qgis_mapserv.fcgi.exe?MAP=C:\qgis\\projects\\catastro.qgz&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities

Esta es una petición GetCapabilities a un servicio WMS, entonces esperamos un XML como respuesta. Si obtienes algo como en la imagen, quiere decir que tu ¡QGIS Server está funcionando y aceptando peticiones!

¿Es así de sencillo?

¡Si! Bueno, también deberías saber acerca de un archivo ce configuración que le dice a Apache que ejecute QGIS Server cada vez que alguien llama:

http://localhost/qgis-ltr/qgis_mapserv.fcgi.exe?

Este archivo está en C:/OSGeo4W/httpd.d/httpd_qgis-ltr.conf

Si te interesa puedes echarle un vistazo al archivo y verás que hay algunas variables de entorno que se definen cada vez que Apache arranca. Estaremos reemplazando ese archivo con configuraciones más avanzadas a lo largo de este post, entonces ténlo presente.

¿Dónde están los datos?

Puedes usar QGIS de escritorio como cliente para los datos que QGIS Server está sirviendo.

Abre QGIS, ve a Capa –> Administrador de fuentes de datos –> WMS/WMTS y agrega una nueva conexión con la URL

http://localhost/qgis-ltr/qgis_mapserv.fcgi.exe?MAP=C:\qgis\\projects\\catastro.qgz&

Elige un nombre para la conexión, yo usaré wms_cadastre.

Adicionalmente, marca la opción “Ignorar orientación de los ejes (WMS 1.3/WMTS)” y haz clic en el botón Aceptar.

En el siguiente diálogo, conéctate al servicio, selecciona ambas capas, elige PNG como formato de salida y cambia el sistema de referencia a “WGS 84 / Pseudo-Mercator” (EPSG: 3857)

Clic en el botón Añadir para cargar las capas a QGIS. Ahora deberías ver algo como esto en el mapa:

¿Pero quién eligió esa simbología para los datos?

Quien publica define la simbología de la capa y otras configuraciones importantes. Deberías configurar tus datos y tus proyectos en QGIS (de escritorio) antes de publicarlos a través de QGIS Server. Este post no cubrirá este tema, pero puedes leer más al respecto en la  documentación de QGIS.

Habilitando plugins de Python para QGIS Server

Para hacer que QGIS Server cargue plugins de Python necesitamos:

1. Configurar un par de variables de entorno en el archivo de configuración de Apache: PYTHONPATH y QGIS_PLUGINPATH.

Por conveniencia, ya hemos definido esas variables por ti en httpd_qgis-ltr_python.conf. Borra el archivo de configuración que está ubicado en C:\OSGeo4W\\httpd.d\, descarga el nuevo desde este enlace y ubícalo en C:\OSGeo4W\\httpd.d\ folder. Ahora renómbralo a httpd_qgis-ltr.conf.

Si quieres, podrías abrir el archivo y observar los valores de PYTHONPATH y QGIS_PLUGINPATH.

Reinicia Apache usando el ícono de ApacheMonitor en la barra de tareas. Si tienes problemas al reiniciar Apache, ve a la sección Resolución de problemas al final del post.

2. Pon tu plugin de Python en la carpeta (C:\qgis\\plugins\) que acabamos de definir en el archivo de configuración de Apache.

Primero, cargaremos un plugin “Hello Server” que responde con un mensaje personalizado cualquier petición donde el parámetro SERVICE sea “Hello” (puede ser en mayúsculas, minúsculas o cualquier combinación).

Entonces, crea la carpeta C:\qgis\\plugins\, descarga este archivo ZIP y extrae su contenido en C:\qgis\\plugins\.

Ve a un navegador web y visita la siguiente URL:

http://localhost/qgis-ltr/qgis_mapserv.fcgi.exe?MAP=C:\qgis\\projects\\catastro.qgz&SERVICE=HELLO

Si todo va bien, en lugar de un XML deberías obtener esta respuesta:

Plugin para el servidor: Restringiendo el acceso a un servicio web geográfico

Ahora que los plugins de Python están habilitados para el servidor, sigamos adelante. QGIS Server nos permite restringir el acceso a capas, objetos espaciales, atributos y los permisos de edición sobre todos ellos. ¡¡¡Estupendo!!!

Descarga el archivo ZIP del plugin “Control Access” desde aquí y extrae su contenido en C:\qgis\\plugins\

De manera predeterminada el plugin no restringe el acceso a ningún dato. Estaremos modificando ligeramente el código Python (solo comentar o descomentar código) para ver el plugin en acción.

Restringir acceso basado en un extent (expresión)

Abre el archivo C:\qgis\\plugins\\access_control\\access_control.py, descomenta la línea 9 y comenta la línea 10. Le estamos diciendo a QGIS Server que bloquee cualquier geometría de cualquier capa que no intersecte el bounding box definido por las coordenadas -8245386.2, 525874.5 and -8245321.2, 525920.4.

Después de guardar el archivo y reiniciar Apache (de nuevo, si tienes problemas reiniciándolo, ve a la sección Resolución de problemas al final de este post), si accedemos de nuevo al servicio deberíamos ver únicamente esto (se agrega el extent en color lila solo para referencia):

Restringir acceso con base en una sentencia WHERE de SQL

Abre el archivo C:\qgis\\plugins\\access_control\\access_control.py, comenta la línea 9 y descomenta la línea 10 para volver al estado inicial del archivo.

Ahora comenta la línea 15 y descomenta la línea 14. Le estamos diciendo a QGIS Server que bloquee cualquier objeto espacial de cualquier capa que no cumpla la (muy restrictiva) condición “fid” = ‘473’.

Luego de guardar el archivo y reiniciar Apache, si accedemos al servicio de nuevo deberíamos ver únicamente esto:

Nota que si activas ambos filtros al tiempo (extent y SQL), solo serán visibles los objetos espaciales que cumplan ambas condiciones. Para el demo, no podrías ver ningún objeto espacial en el servicio, puesto que ningún objeto espacial cumpliría ambas condiciones.

Restringir acceso a capas

De manera predeterminada el servicio publicado en este demo le permite a los usuarios leer y editar geometrías en ambas capas: ‘terreno’ y ‘construccion’. En este ejemplo quitaremos el permiso de lectura y edición sobre la capa ‘construccion’.

Abre el archivo C:\qgis\\plugins\\access_control\\access_control.py, comenta la línea 14 y descomenta la línea 15 para regresar al estado inicial del archivo.

Ahora descomenta las líneas 19-22 y esta vez no comentes ninguna línea. Le estamos diciendo a QGIS Server que elimine el acceso a la capa ‘construccion’. El resto de capas (es decir, ‘terreno’) mantendrán el nivel de acceso definido en el proyecto de QGIS base del servicio (esto es, acceso completo de lectura y edición).

Luego de guardar el archivo y reiniciar Apache, si accedemos de nuevo al servicio ni siquiera veremos la capa ‘construccion’ en el listado de capas ofrecidas por el servicio:

Restringir acceso a atributos de una capa

El servicio publicado en este demo le permite a los usuarios leer todos los atributos ofrecidos por el servicio. Veremos cómo permitir el acceso solo a un subconjunto de atributos.

Abre el archivo C:\qgis\\plugins\\access_control\\access_control.py  y comenta las líneas 19-22 para regresar al estado inicial del archivo.

Ahora comenta la línea 29 y descomenta la línea 28. Le estamos diciendo a QGIS Server que solo permita el acceso a los atributos ‘area_terreno’ y ‘avaluo_terreno’.

Luego de guardar el archivo y reiniciar Apache, si accedemos de nuevo al servicio solo deberíamos ver los atributos ‘area_terreno’ y ‘avaluo_terreno’ al realizar una operación GetFeatureInfo (identificar objetos espaciales en QGIS). En la siguiente imagen puedes ver la diferencia antes (lado izquierdo) y después (lado derecho) que aplicamos la regla:

Restringir edición de objetos espaciales específicos

El servicio que publicamos permite permite que los usuarios editen todos los datos de ambas capas. Veremos cómo permitir la edición solo a un subconjunto de objetos espaciales en la capa ‘construccion’, mientras todos los objetos espaciales en la capa ‘terreno’ seguirán siendo editables.

Abre el archivo C:\qgis\\plugins\\access_control\\access_control.py, comenta la línea 28 y descomenta la línea 29 para regresar al estado inicial del archivo.

Ahora descomenta las líneas 33-34. Le estamos diciendo a QGIS Server que permita la edición de todos los objetos espaciales de la capa ‘terreno’ pero solo permita la edición de los objetos espaciales cuyo campo ‘fid’ tiene valores entre 67 y 80 en la capa ‘construccion’.

Luego de guardar y reiniciar Apache, esta vez nos gustaría probar el acceso de edición a los datos. En lugar de un servicio WMS, este caso de uso requiere un WFS.

Agrega un nuevo servicio WFS a QGIS (Capa –> Administrador de fuentes de datos –> WFS) con la siguiente URL (la misma URL que ya usaste para el WMS):

http://localhost/qgis-ltr/qgis_mapserv.fcgi.exe?MAP=C:\qgis\\projects\\catastro.qgz&

Elige un nombre para la conexión, yo usaré wfs_cadastre.

Adicionalmente, elige la versión 1.1 y haz clic en el botón Aceptar.

Ahora puedes intentar editar objetos espaciales resaltados en la captura de pantalla de abajo. Esos son los objetos espaciales en la capa ‘construccion’, cuyo ‘fid’ está entre 67 y 80.

La edición de los objetos espaciales resaltados debería ser posible, pero una vez que intentes editar otros objetos espaciales deberías obtener un error como este:

Plugin de servidor: Restringiendo el acceso a un servicio web geográfico con base en roles de usuario

El próximo paso es restringir el acceso al servicio con base en el rol al cual pertenece un usuario autenticado.

El caso de estudio es la administración de tierras, donde varios actores (propietarios, autoridades catastrales, oficinas de registro, organizaciones medioambientales, oficinas de planeación, entre otras) requieren acceso a información catastral. Sin embargo, todos los actores deberían poder acceder únicamente al subconjunto de datos que realmente necessitan para su propósito.

Afortunatamente, confiigurar un escenario así de complejo es relativamente simple usando QGIS Server y un plugin de Python.

Para aclarar, tendremos un solo proyecto de QGIS y publicaremos solamente un servicio WMS y un servicio WFS. QGIS Server y su API para Python se encargarán del resto.

Ahora no necesitamos el plugin “Access Control” que usamos en el ejercicio anterior, entonces borra su directorio o edita su archivo metadata.txt y cambia su variable “server” a Falso, para de esta forma evitar que QGIS Server lo cargue.

Configurando la autenticación de usuarios en Apache e instalando el plugin ‘Access control with users’ para QGIS Server

Antes de instalar y configurar nuestro plugin de Python, configuraremos el servidor Apache para que soporte autenticación de usuarios. Dado el alcance de este post, trabajaremos con autenticación básica. Por supuesto, en un ambiente de producción deberías trabajar con mecanismos de autenticación más seguros.

Sigue estos 5 pasos para configurar Apache y QGIS Server:

1. Usa nuestro httpd_qgis-ltr_auth.conf

Ya hemos configurado un archivo para ti que incluye algunas directivas que le dicen a Apache que queremos restringir el acceso a nuestro QGIS Server. Usando dicho archivo también especificamos la ubicación de un archivo que almacena usuarios y contraseñas llamado htpasswd. Para este ejercicio lo ubicaremos en C:\qgis\\htpasswd (en producción deberías restringir el acceso a esa carpeta).

Borra el archivo de configuración actual ubicado en C:\OSGeo4W\\httpd.d\, descarga un nuevo archivo desde aquí y ubícalo en la carpeta C:\OSGeo4W\\httpd.d\. Ahora renómbralo a httpd_qgis-ltr.conf.

2. Usa htpasswd.exe para crear usuarios

Abre una terminarl de comandos y ejecuta:

C:\OSGeo4W\\apache\\bin\\htpasswd.exe -c C:\qgis\\htpasswd germap

para crear el usuario ‘germap’. Te preguntarán la contraseña para el nuevo usuario. Para evitar olvidarla (tendremos varios usuarios) y solo porque esto es un demo, uso el mismo nombre de usuario como contraseña.

Continúa creando los siguientes usuarios ejecutando el mismo comando, pero esta vez removiendo el parámetro -c (que implica crear el archivo): susan, pablo, isabel, sandra, XYZ, luis y norah.

3. Habilita el móduo ‘rewrite’ de Apache

Abre C:\OSGeo4W\\apache\\conf\\httpd.conf y descomenta la línea “LoadModule rewrite_module modules/mod_rewrite.so”. En mi instalación es la línea 116. Esto le permite a Apache escribir el usuario autenticado en la variable de entorno HTTP_AUTHORIZATION, para que podamos accederla en nuestra sesión de servidor.

4. Habilitar el plugin ‘Access control with users’ para QGIS Server

Descarga el archivo ZIP del plugin ‘Access control with users’  desde aquí y extrae su contenido en C:\qgis\\plugins\

Observa que dentro de la carpeta del plugin encontrarás un archivo access_control.py que conoce cuál usuario está accediendo el servicio y también lee un archivo de configuración para restringir el acceso de lectura y edición a capas, objetos espaciales y atributos. El archivo config.py relaciona los usuarios con sus roles y define permisos para cada rol.

Esta es la lista de usuarios autorizados con sus correspondientes roles (archivo config.py):

germap (ID doc: 80199143) –> owners
susan (ID doc: 1000123456) –> owners
pablo –> authority
isabel –> authority
sandra –> property_registration_office
XYZ –> constructors
luis –> guest

5. Reiniciar Apache

Finalmente, reinicia Apache para que lea las nuevas configuraciones, así como el nuevo plugin para QGIS Server.

Caso de estudio: Administración de Tierras

En este escenario sencillo de Administración de Tierras, hay una autoridad catastral que está a cargo de publicar el servicio. Los usuarios que pertenecen a dicha organización son los únicos que pueden acceder con permiso de lectura y escrituraa todos los datos: capa ‘terreno’ y capa ‘construccion’. Puedes empezar a revisar el archivo config.py file dentro de la carpeta del plugin para ver los permisos definidos para cada actor.

Los propietarios tienen acceso de solo lectura a todos los datos relacionados a sus propiedades. Sabemos cuáles son sus propiedades porque tienen asociado el número de documento de identidad del propietario.

Los usuarios de la oficina de registro de la propiedad tienen acceso de solo lectura a todos los datos, excepto a los atributos de avalúos.

Los usuarios de compañías de construcción pueden estar interesados en adquirir algunos terrenos para próximos proyectos. Ellos pertenecen al rol ‘constructors‘ y tienen acceso de solo lectura a la capa ‘terreno’, pero no pueden ver atributos diferentes a los de avalúos.

Los usuarios autenticados bajo el rol guest (invitado) tienen acceso de solo lectura a todas las geometrías pero el único atributo que pueden ver es el identificador del objeto espacial.

Y finalmente, los usuarios autenticados en Apache pero que no tienen rol asignado en el archivo config.py file, no tienen acceso a ningún dato.

Conectándose a servicios como usuario autenticado

WMS:

Abre QGIS de escritorio, ve a Capa –> Administrador de fuentes de datos –> WMS/WMTS, elige la conexión wms_cadastre creada en pasos anteriores y dale clic al botón Editar.

Ve a la sección Autenticación y elige la pestaña “Básica”. Allí puedes ingresar las credenciales del usuario para acceder al servicio:

Ahora haz clic en Aceptar y luego en el botón Conectar para obtener las capas disponibles como usuario autenticado.

WFS:

Ve a Capa –> Administrador de fuentes de datos –> WFS y edita la conexión wfs_cadastre, definiendo una autenticación básica:

Click en Acpetar y luego en Conectar para obtener un listado de capas disponibles para el usuario autenticado.

Usuarios con el rol ‘owners’ (propietarios)

Acceso de solo lectura a todos los datos relacionados a sus propiedades. Sabemos cuáles son sus propiedades porque tienen un campo con el número de documento de identidad.

USUARIO: germap (Documento de identidad: 80199143)

USUARIA: susan (Documento de identidad: 1000123456)

Usuarios con rol ‘authority’ (autoridad catastral)

Acceso de lectura y escritura para todos los datos.

USUARIO: pablo

Usuarios con el rol ‘property_registration_office’ (oficina de registro)

Acceso de solo lectura a todos los datos, pero no tienen acceso a los atributos de avalúos. Esto es, para la capa ‘terreno’, los campos ‘avaluo_terreno’ y ‘predio_avaluo_predio’ no se mostrarán. Similarmente, para la capa ‘construccion’, el campo ‘avaluo_construccion’ no estará disponible.

USUARIA: sandra

Usuarios con el rol ‘constructors’ (constructores)

Acceso de solo lectura a la capa ‘terreno’, pero no pueden ver atributos diferentes al avalúo.

USUARIO: XYZ

Usuarios con rol ‘guest’ (invitado)

Acceso de solo lectura a todas las geometrías, pero el único atributo que pueden ver es el identificador del objeto espacial.

USUARIO: luis

Usuarios autenticados en Apache pero sin rol asignado en QGIS Server

No tienen acceso a ningún dato.

USUARIA: norah

Ahora, puedes continuar verificando que la edición está habilitada/deshabilitada de manera adecuada con base en los roles de los usuarios.

¡Y eso es todo! Espero que estés list@ para empezar algunos proyectos interesantes con QGIS Server. ¡Que te diviertas!

Notas

  • El archivo config.py es solo una manera de manejar usuarios y roles. Idealmente, deberías tener una aplicación (sea de esritorio o web) que te permita administrar usuarios y roles y los datos estarían almacenados en una base de datos.
  • Agregando más lógica al plugin ‘Access control with users’ y más datos al archivo config.py, podrías configurar más aspectos de los servicios. Por ejemplo, no debería ser complicado dejar accesible el servicio WMS, pero quitar el permiso de lectura sobre el WFS correspondiente. ¿Te gustaría intentarlo ;)?

Resolución de problemas

¿No puedes iniciar/reiniciar el servidor Apache usando Apache Monitor?

Si obtienes un mensaje que dice “The requested operation has failed!” intentando iniciar/reiniciar tu servidor Apache con Apache Monitor, ve al administrador de tareas (Ctrl+Alt+Del) y termina la tarea “Apache HTTP Server”. Ahora inicia tu servidor Apache usando Apache Monitor y verás que ahora todo funciona normalmente.

Referencias

Este post está basado en el trabajo de Alessandro Pasotti’s. Principalmente en su presentación: Introduction to QGIS Server