通过LDAP的Geonode身份验证

此软件包提供使用LDAP作为geonode的身份验证和授权后端的实用程序。

这个 django_auth_ldap 包是添加LDAP与Django项目集成的一种非常有效的方式。它在将LDAP用户映射到geonode用户方面提供了很大的灵活性,并且能够管理用户身份验证。

但是,为了完全支持将LDAP组映射到geonode,并强制实施对资源的组权限,需要自定义geonode身份验证后端。这个contrib包提供了这样一个后端,它基于 django_auth_ldap

安装

安装此contrib软件包需要执行以下操作:

  1. 安装地理节点

  2. 安装系统LDAP库(需要开发包)

  3. 本地克隆此存储库

  4. 更改为 ldap 目录并安装此contrib软件包

# 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 .

配置

  1. 添加 geonode_ldap.backend.GeonodeLdapBackend 作为额外的身份验证后端。

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

    您可以使用其他身份验证后端,Django身份验证框架会根据设置中列出的顺序尝试所有这些后端。这意味着可以这样设置geonode:允许内部组织用户使用其LDAP凭据登录,同时允许临时用户使用他们的Facebook登录(只要您启用了Facebook社交身份验证提供程序)。

    注解

    姜戈一家 django.contrib.auth.backends.ModelBackend 还必须使用才能提供与LDAP的完全地理节点集成。但是,这在GeoNode上默认包含 settings

    # 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. 设置一些附加配置值。其中一些变量以前缀 AUTH_LDAP (它们由以下人员直接使用 django_auth_ldap ),而其他则以前缀 GEONODE_LDAP (它们由以下人员使用 geonode_ldap )。geonode自定义变量包括:

    • GEONODE_LDAP_GROUP_PROFILE_FILTERSTR +这是一个带有过滤的ldap搜索片段,允许查询现有组。请参见下面的示例

    • GEONODE_LDAP_GROUP_NAME_ATTRIBUTE -这是将用于派生地理节点组名称的LDAP属性的名称。如果未指定,则默认为 cn ,这意味着LDAP对象的 common name 将用于生成地理结点组的名称

    • GEONODE_LDAP_GROUP_PROFILE_MEMBER_ATTR - This is the name of the LDAP attribute that will be used for deriving the geonode membership. If not specified it will default to member

示例配置:

# 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')

示例环境变量:

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

上面示例中看到的配置将允许LDAP用户使用其LDAP凭据登录到geonode。

首次登录时,将根据LDAP用户及其LDAP属性创建一个geonode用户 cnsn 用于填充geonode用户的 first_namelast_name 配置文件字段。

LDAP中用户所属的任何组(位于 cn=groups,dc=ad,dc=example,dc=org 搜索库,并且属于以下其中之一 (|(cn=abt1)(cn=abt2)(cn=abt3)(cn=abt4)(cn=abt5)(cn=abt6)) 组)将被映射到相应的geonode组,甚至在geonode中创建这些组,以防它们尚不存在。geonode用户也成为这些geonode组的成员。

每次登录时,系统都会根据从LDAP提取的信息重新评估用户的地理节点组成员身份。这个 AUTH_LDAP_MIRROR_GROUPS_EXCEPT 设置可用于指定不会重新评估其成员身份的组。

如果不应镜像任何LDAP组 LDAP_MIRROR_GROUPSLDAP_MIRROR_GROUPS_EXCEPT 必须设置为 False

注解

从LDAP映射的用户将标记为 ldap 标签。这将用于使它们保持同步。

警告

如果您删除 ldap 标记后,用户将作为纯内部GeoNode用户受到威胁。

您也可以在用户登录之前提前手动生成地理节点组。在这种情况下,当用户登录且映射的LDAP组已存在时,仅将该用户添加到地理节点组

一定要结账离开。 django_auth_ldap 有关各种配置选项的详细信息,请参阅。

使用户和组保持同步

为了不间断地保留远程LDAP用户和组 已同步 使用GeoNode,您将需要定期运行一些特定的管理命令。

*/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

其中 manage.sh 是一个类似于以下内容的bash脚本:

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 $@

以及 /opt/geonode/my-geonode/.env 类似于以下内容:

/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

注解

您可能希望使用相同的 /opt/geonode/my-geonode/.env 为您的 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

用于集中监控/分析的Geonode Logstash

通过此contrib应用程序以及GeoNode内部监控应用程序,管理员可以配置将指标数据发送到 集中式服务器 它伴随着 Logstash

因此,可以在应用程序外部可视化有关一个或多个GeoNode实例的统计数据和图表。将服务器配置为 ELK stack 例如,可以在Kibana仪表板上可视化这些信息。

如果您管理多个GeoNode实例,则该服务器可以从多个GeoNode接收数据,从而使这两个实例都可用 single-instance dashboards (指个别实例)和 全局控制面板 (针对整个实例集计算的统计信息)。

警告

如果设置变量为 USER_ANALYTICS_ENABLEDmonitoring-enabled 设置为 False

概述

默认情况下,GeoNode将每隔一段时间向集中式服务器发送数据 3600秒 (1小时)因此,如果启用,监控应用将收集1小时聚合的数据。此时间间隔可以配置,请参阅下面的段落以了解如何配置。

格式化和压缩的数据将在 TCP 连接(在 443 standard port by default) through a scheduled celery task which basically logs information via python-logstash-async

警告

此功能需要 python-logstash-async

数据和事件格式

每次调用集中监控服务时,4种类型的 JSON 格式化的事件将发送到服务器:

  1. 实例概述

{
  "format_version": "1.0",
  "instance": {
    "name": geonode instance HOSTNAME,
    "ip": geonode instance IP
  },
  "time": {
    "startTime": UTC now - 1 hour (default)
    "endTime": UTC now
  },
  "hits": total number of requests,
  "unique_visits": total number of unique sessions,
  "unique_visitors": total number of unique users,
  "registered_users": total number of registered users at the end time,
  "layers": total number of layers at the end time,
  "documents": total number of documents at the end time,
  "maps": total number of maps at the end time,
  "errors": total number of errors
}
  1. 资源详细信息

{
  "format_version": "1.0",
  "instance": {
    "name": geonode instance HOSTNAME,
    "ip": geonode instance IP
  },
  "time": {
    "startTime": UTC now - 1 hour (default)
    "endTime": UTC now
  },
  "resources": [
    …
    {
        "type": resource type,
        "name": resource name,
        "url": resource URL,
        "hits": total number of requests about this resource,
        "unique_visits": total number of unique sessions about this resource,
        "unique_visitors": total number of unique users about this resource,
        "downloads": total number of resource downloads,
        "ogcHits": total number of OGC service requests about this resource,
        "publications": total number of publication events
    },
    …
  ]
}
  1. 国家/地区详细信息

{
  "format_version": "1.0",
  "instance": {
    "name": geonode instance HOSTNAME,
    "ip": geonode instance IP
  },
  "time": {
    "startTime": UTC now - 1 hour (default)
    "endTime": UTC now
  },
  "countries": [
    …
    {
        "name": country name,
        "hits": total number of requests about the country
    },
    …
  ]
}
  1. UA(用户代理)系列详细信息

{
  "format_version": "1.0",
  "instance": {
    "name": geonode instance HOSTNAME,
    "ip": geonode instance IP
  },
  "time": {
    "startTime": UTC now - 1 day
    "endTime": UTC now
  },
  "ua_families": [
    …
    {
        "name": UA family name
        "hits": total number of requests about the UA family
    },
    …
  ]
}

这些消息将是 gzip 压缩以提高传输性能,并且它们应该由 logstash filter 在服务器端(请参见 Logstash配置 )。

配置

默认情况下,集中监控服务处于禁用状态,因为它需要内部监控处于活动状态,并且需要特定于服务的配置。

地理节点配置

在GeoNode端,可以从Django管理界面设置所有需要的配置。
如果启用,则 GEONODE LOGSTASH 部分将显示 集中式服务器 功能:
来自管理用户界面的集中式服务器

让我们添加一个:

集中式服务器设置

这个 Host IP地址和 Port 号码是必填的,时间也是必填的 间隔 (缺省情况下为3600秒),它定义了服务调用轮询(因此应该聚合数据的时间范围)。

注解

配置服务后,用户可以通过单击 测试连接 。它将测试与集中式服务器的连接,而不保存配置。

其他设置附带默认值:

  • 数据库路径 -->本地Spatialite数据库,用于缓存发送和传输到Logstash服务器之间的事件(即使在进程重启和崩溃时也会缓存日志事件);

  • 套接字超时 -->TCP连接超时(秒);

  • 队列检查间隔 -->检查内部队列中是否有需要缓存到数据库中的新消息的时间间隔(秒);

  • 队列事件刷新间隔 -->将缓存的事件从数据库发送到Logstash的时间间隔(秒);

  • 队列事件刷新计数 -->从数据库发送到Logstash的缓存事件计数;

  • 队列事件批量大小 -->一批发送到Logstash的最大事件数;

  • Logstash数据库超时 -->‘连接’Spatialite数据库的超时时间(秒)。

要更好地理解这些变量的含义,建议阅读 python-logstash-async options for the asynchronous processing and formatting

其他三个只读字段将可见:

  • 上次成功交付 -->上次交付成功的时间戳(如果存在);

  • 下一次计划交付 -->下一次定时交货的时间戳;

  • 上次传递失败 -->上次传递失败的时间戳(如果存在)。

Logstash配置

在服务器端,应该设置正确的Logstash配置。
某些事件格式包含数组(请参见 数据和事件格式 ),因此Logstash应该能够为数组的每个元素检索单个事件。这个 Split filter plugin 帮助正确解析这些消息。
如上所述,事件消息将被gzip压缩,因此 Gzip_lines codec plugin 应该与Logstash一起安装,并且“gzip_lines”编解码器应该用于 tcp 输入。

日志堆栈配置示例:

input {
  tcp {
    port => <logstash_port_number>
    codec => "gzip_lines"
  }
}

filter {
  json {
    source => "message"
  }
  if [format_version] == "1.0" {
    if [countries] {
      split {
        field => "countries"
      }
    }
    if [resources] {
      split {
        field => "resources"
      }
    }
    if [ua_families] {
      split {
        field => "ua_families"
      }
    }
    mutate {
      remove_field => "message"
    }
  }
  geoip {
    source => "[instance][ip]"
  }
}

output {
  elasticsearch {
    hosts => "elasticsearch:<elastic_port_number>"
    index => "logstash-%{[instance][name]}-%{+YYYY.MM.dd}"
    user => "elastic"
    password => "changeme"
  }
  stdout { codec => rubydebug }
}

用法

保存服务配置时,如果启用了监控,则GeoNode将创建/更新芹菜 Periodic Task 它将根据 间隔 已配置。

您可以在 周期性任务 管理员UI的部分:

定期任务部分

这个 dispatch-metrics-task 任务:

派单指标任务

任务详细信息:

调度指标任务详细信息

警告

当禁用监视是 良好实践 以同时禁用相应的定期任务。

管理命令

除了计划任务外,此Conrib应用程序还使 dispatch_metrics 命令手动将度量发送到服务器。
显然,所考虑的时间间隔将从上次成功交付开始,并在当前时间结束。

启用监控插件时 (USER_ANALYTICS_ENABLEDmonitoring-enabled 设置为 True )和一个 用于集中监控/分析的Geonode Logstash 配置后,Geonode会将指标数据(默认情况下为每小时)发送到外部服务器(该服务器随Logstash一起提供),以进行统计可视化和分析。

该命令可以使用 manage.py 剧本。不需要任何选项。

$ DJANGO_SETTINGS_MODULE=<your_settings_module> python manage.py dispatch_metrics

执行过程中可能引发的异常将报告到GeoNode日志。