Autenticación de Geonode a través de LDAP

Este paquete proporciona utilidades para utilizar LDAP como back-end de autenticación y autorización para geonode.

El paquete django_auth_ldap es una forma muy eficaz de agregar integración LDAP a los proyectos de Django. Proporciona mucha flexibilidad para asignar usuarios LDAP a usuarios de GeoNode y puede administrar la autenticación de usuarios.

Sin embargo, para proporcionar soporte completo para mapear grupos LDAP con GeoNode y hacer cumplir los permisos de grupo en los recursos, se requiere un backend de autenticación de GeoNode personalizado. Este paquete de contribuciones proporciona dicho backend, basado en django_auth_ldap.

Instalación

Instalar este paquete contrib es una cuestión de:

  1. Instalar GeoNode

  2. Instalar las bibliotecas LDAP del sistema (se necesitan paquetes de desarrollo)

  3. Clonar este repositorio localmente

  4. Cambar al directorio ldap e instalar este paquete de contribuciones

# 1. install geonode (not shown here for brevity)
# 2. install systemwide LDAP libraries
sudo apt install \
    libldap2-dev \
    libsasl2-dev

# 3. get geonode/contribs code
git clone https://github.com/GeoNode/geonode-contribs.git

# 4. install geonode ldap contrib package
cd geonode-contribs/ldap
pip install .

Configuración

  1. Agrega geonode_ldap.backend.GeonodeLdapBackend como un backend de autenticación adicional.

    # e.g. by updating your settings.py or local_settings.py
    AUTHENTICATION_BACKENDS += (
        "geonode_ldap.backend.GeonodeLdapBackend",
    )
    

    Puedes utilizar backends de autenticación adicionales. El marco de autenticación de Django los prueba todos según el orden indicado en la configuración. Esto significa que Geonode se puede configurar de manera que permita que los usuarios internos de la organización inicien sesión con sus credenciales LDAP, mientras que al mismo tiempo permite que los usuarios ocasionales utilicen su inicio de sesión de Facebook (siempre que habilite el proveedor de autenticación social de Facebook).

    Nota

    También se debe utilizar django.contrib.auth.backends.ModelBackend de Django para proporcionar una integración completa de GeoNode con LDAP. Sin embargo, esto está incluido de manera predeterminada en la configuración de GeoNode

    # The GeoNode default settings are the following
    AUTHENTICATION_BACKENDS = (
        'oauth2_provider.backends.OAuth2Backend',
        'django.contrib.auth.backends.ModelBackend',
        'guardian.backends.ObjectPermissionBackend',
        'allauth.account.auth_backends.AuthenticationBackend',
    )
    
  2. Establece algunos valores de configuración adicionales. Algunas de estas variables tienen el prefijo AUTH_LDAP (son utilizadas directamente por django_auth_ldap) mientras que otras tienen el prefijo GEONODE_LDAP (son utilizadas por geonode_ldap). Las variables personalizadas de GeoNode son:

    • GEONODE_LDAP_GROUP_PROFILE_FILTERSTR: este es un fragmento de búsqueda LDAP con el filtro que permite consultar grupos existentes. Ve el ejemplo a continuación

    • GEONODE_LDAP_GROUP_NAME_ATTRIBUTE: este es el nombre del atributo LDAP que se utilizará para derivar el nombre del grupo de GeoNode. Si no se especifica, el valor predeterminado será cn, lo que significa que el nombre común del objeto LDAP se utilizará para generar el nombre del grupo de GeoNode

    • GEONODE_LDAP_GROUP_PROFILE_MEMBER_ATTR: este es el nombre del atributo LDAP que se utilizará para derivar la membresía de GeoNode. Si no se especifica, el valor predeterminado será member

Configuración de ejemplo:

# add these import lines to the top of your geonode settings file
from django_auth_ldap import config as ldap_config
from geonode_ldap.config import GeonodeNestedGroupOfNamesType
import ldap

# enable logging
import logging
logger = logging.getLogger('django_auth_ldap')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

# add both standard ModelBackend auth and geonode.contrib.ldap auth
AUTHENTICATION_BACKENDS += (
    'geonode_ldap.backend.GeonodeLdapBackend',
)

# django_auth_ldap configuration
AUTH_LDAP_SERVER_URI = os.getenv("LDAP_SERVER_URL")
AUTH_LDAP_BIND_DN = os.getenv("LDAP_BIND_DN")
AUTH_LDAP_BIND_PASSWORD = os.getenv("LDAP_BIND_PASSWORD")
AUTH_LDAP_USER_SEARCH = ldap_config.LDAPSearch(
    os.getenv("LDAP_USER_SEARCH_DN"),
    ldap.SCOPE_SUBTREE,
    os.getenv("LDAP_USER_SEARCH_FILTERSTR")
)
# should LDAP groups be used to spawn groups in GeoNode?
AUTH_LDAP_MIRROR_GROUPS = strtobool(os.getenv("LDAP_MIRROR_GROUPS", 'True'))
AUTH_LDAP_GROUP_SEARCH = ldap_config.LDAPSearch(
    os.getenv("LDAP_GROUP_SEARCH_DN"),
    ldap.SCOPE_SUBTREE,
    os.getenv("LDAP_GROUP_SEARCH_FILTERSTR")
)
AUTH_LDAP_GROUP_TYPE = GeonodeNestedGroupOfNamesType()
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mailPrimaryAddress"
}
AUTH_LDAP_FIND_GROUP_PERMS = True
AUTH_LDAP_MIRROR_GROUPS_EXCEPT = [
    "test_group"
]

# these are not needed by django_auth_ldap - we use them to find and match
# GroupProfiles and GroupCategories
GEONODE_LDAP_GROUP_NAME_ATTRIBUTE = os.getenv("LDAP_GROUP_NAME_ATTRIBUTE", default="cn")
GEONODE_LDAP_GROUP_PROFILE_FILTERSTR = os.getenv("LDAP_GROUP_SEARCH_FILTERSTR", default='(ou=research group)')
GEONODE_LDAP_GROUP_PROFILE_MEMBER_ATTR = os.getenv("LDAP_GROUP_PROFILE_MEMBER_ATTR", default='member')

Ejemplo de variables de entorno:

LDAP_SERVER_URL=ldap://<the_ldap_server>
LDAP_BIND_DN=uid=ldapinfo,cn=users,dc=ad,dc=example,dc=org
LDAP_BIND_PASSWORD=<something_secret>
LDAP_USER_SEARCH_DN=dc=ad,dc=example,dc=org
LDAP_USER_SEARCH_FILTERSTR=(&(uid=%(user)s)(objectClass=person))
LDAP_MIRROR_GROUPS=True
LDAP_GROUP_SEARCH_DN=cn=groups,dc=ad,dc=example,dc=org
LDAP_GROUP_SEARCH_FILTERSTR=(|(cn=abt1)(cn=abt2)(cn=abt3)(cn=abt4)(cn=abt5)(cn=abt6))
LDAP_GROUP_PROFILE_MEMBER_ATTR=uniqueMember

La configuración que se ve en el ejemplo anterior permitirá a los usuarios LDAP iniciar sesión en GeoNode con sus credenciales LDAP.

En el primer inicio de sesión, se crea un usuario de GeoNode a partir del usuario LDAP y sus atributos LDAP cn y sn se utilizan para completar los campos de perfil first_name y last_name del usuario de GeoNode.

Cualquier grupo del que el usuario sea miembro en LDAP (bajo la base de búsqueda cn=groups,dc=ad,dc=example,dc=org y perteneciente a uno de los grupos (|(cn=abt1)(cn=abt2)(cn=abt3)(cn=abt4)(cn=abt5)(cn=abt6))) se mapeará a los correspondientes grupos en GeoNode, incluso creando estos grupos en GeoNode en caso de que aún no existan. El usuario de GeoNode también se convertirá en miembro de estos grupos en GeoNode.

En cada inicio de sesión, las membresías del grupo de GeoNode del usuario se vuelven a evaluar según la información extraída de LDAP. La configuración AUTH_LDAP_MIRROR_GROUPS_EXCEPT se puede utilizar para especificar los grupos cuyas membresías no se volverán a evaluar.

Si no se reflejarán grupos LDAP, LDAP_MIRROR_GROUPS y LDAP_MIRROR_GROUPS_EXCEPT deben establecerse en Falso.

Nota

Los usuarios asignados desde LDAP se marcarán con una etiqueta «ldap». Esto se utilizará para mantenerlos sincronizados.

Advertencia

Si eliminas la etiqueta ldap, los usuarios serán tratados como usuarios puramente internos de GeoNode.

También puedes generar manualmente los grupos de GeoNode de antemano, antes de que los usuarios inicien sesión. En este caso, cuando un usuario inicie sesión y el grupo LDAP mapeado ya exista, el usuario simplemente se añadirá al grupo de GeoNode

Asegúrate de consultar django_auth_ldap para obtener más información sobre las distintas opciones de configuración.

Mantenga sincronizados a los usuarios y grupos

Para mantener constantemente sincronizados los usuarios y grupos LDAP remotos con GeoNode, necesitará ejecutar periódicamente algunos comandos de administración específicos.

*/10 * * * * /opt/geonode/my-geonode/manage.sh updateldapgroups  >> /var/log/cron.log 2>&1
*/10 * * * * /opt/geonode/my-geonode/manage.sh updateldapusers   >> /var/log/cron.log 2>&1

Donde manage.sh es un script bash similar al siguiente:

manage.sh

export $(grep -v '^#' /opt/geonode/my-geonode/.env | xargs -d '\n'); /home/<my_user>/.virtualenvs/geonode/bin/python /opt/geonode/my-geonode/manage.py $@

y el /opt/geonode/my-geonode/.env es algo similar a lo siguiente:

/opt/geonode/my-geonode/.env

DEBUG=False
DJANGO_ALLOWED_HOSTS=<geonode_public_host>,localhost,127.0.0.1
DJANGO_DATABASE_URL=postgis://my_geonode:**********@localhost:5432/my_geonode_db
DEFAULT_BACKEND_UPLOADER=geonode.importer
DEFAULT_FROM_EMAIL=geonode@example.org
DJANGO_EMAIL_HOST=smtp.example.org
DJANGO_EMAIL_HOST_PASSWORD=**********
DJANGO_EMAIL_HOST_USER=geonode
DJANGO_EMAIL_PORT=465
DJANGO_EMAIL_USE_SSL=True
DJANGO_SETTINGS_MODULE=my_geonode.settings
DJANGO_SECRET_KEY=**********
OAUTH2_API_KEY=**********
PROXY_URL=/proxy/?url=
EXIF_ENABLED=True
EMAIL_ENABLE=True
TIME_ENABLED=True
ACCOUNT_OPEN_SIGNUP=True
ACCOUNT_APPROVAL_REQUIRED=True
ACCOUNT_EMAIL_REQUIRED=True
ACCOUNT_EMAIL_VERIFICATION=optional
AVATAR_GRAVATAR_SSL=True
GEONODE_DB_URL=postgis://my_geonode:**********@localhost:5432/my_geonode_data
GEOSERVER_ADMIN_PASSWORD=**********
GEOSERVER_LOCATION=https://<geonode_public_host>/geoserver/
GEOSERVER_PUBLIC_HOST=<geonode_public_host>
GEOSERVER_PUBLIC_LOCATION=https://<geonode_public_host>/geoserver/
GEOSERVER_WEB_UI_LOCATION=https://<geonode_public_host>/geoserver/
LDAP_SERVER_URL=ldap://<the_ldap_server>
LDAP_BIND_DN=uid=ldapinfo,cn=users,dc=ad,dc=example,dc=org
LDAP_BIND_PASSWORD=<something_secret>
LDAP_USER_SEARCH_DN=dc=ad,dc=example,dc=org
LDAP_USER_SEARCH_FILTERSTR=(&(uid=%(user)s)(objectClass=person))
LDAP_MIRROR_GROUPS=True
LDAP_GROUP_SEARCH_DN=cn=groups,dc=ad,dc=example,dc=org
LDAP_GROUP_SEARCH_FILTERSTR=(|(cn=abt1)(cn=abt2)(cn=abt3)(cn=abt4)(cn=abt5)(cn=abt6))
LDAP_GROUP_PROFILE_MEMBER_ATTR=uniqueMember
OGC_REQUEST_MAX_RETRIES=3
OGC_REQUEST_POOL_CONNECTIONS=100
OGC_REQUEST_POOL_MAXSIZE=100
OGC_REQUEST_TIMEOUT=60
SITEURL=https://<geonode_public_host>/
SITE_HOST_NAME=<geonode_public_host>
FREETEXT_KEYWORDS_READONLY=False
# Advanced Workflow Settings
ADMIN_MODERATE_UPLOADS=False
GROUP_MANDATORY_RESOURCES=False
GROUP_PRIVATE_RESOURCES=False
RESOURCE_PUBLISHING=False

Nota

Es posible que también desees utilizar el mismo /opt/geonode/my-geonode/.env para tu configuración UWSGI:

[uwsgi]
socket = 0.0.0.0:8000
uid = <my_user>
gid = www-data

plugins = python3
virtualenv = /home/<my_user>/.virtualenvs/geonode

# set environment variables from .env file
env LANG=en_US.utf8
env LC_ALL=en_US.UTF-8
env LC_LANG=en_US.UTF-8

for-readline = /opt/geonode/my-geonode/.env
    env = %(_)
endfor =

chdir = /opt/geonode/my-geonode
module = my_geonode.wsgi:application

processes = 12
threads = 2
enable-threads = true
master = true

# logging
# path to where uwsgi logs will be saved
logto = /storage/my_geonode/logs/geonode.log
daemonize = /storage/my_geonode/logs/geonode.log
touch-reload = /opt/geonode/my-geonode/my_geonode/wsgi.py
buffer-size = 32768
max-requests = 500
harakiri = 300 # respawn processes taking more than 5 minutes (300 seconds)
# limit-as = 1024 # avoid Errno 12 cannot allocate memory
harakiri-verbose = true
vacuum = true
thunder-lock = true