通过LDAP进行地理节点身份验证

这个包提供了使用ldap作为geonode的身份验证和授权后端的实用程序。

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

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

安装

安装此contrib包是一个:

  1. 安装geonode

  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 social auth provider)。

    注解

    Django家 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 -这是将用于派生geonode组名称的ldap属性的名称。如果未指定,则默认为 cn ,这意味着LDAP对象 common name 将用于生成geonode组的名称

    • 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

# 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")
)
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_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组,甚至在GeNODE中创建这些组,以防它们还不存在。geonode用户也成为这些geonode组的成员。

每次登录时,都会根据从ldap提取的信息重新评估用户的geonode组成员身份。这个 AUTH_LDAP_MIRROR_GROUPS_EXCEPT 设置可用于指定其成员身份将不会重新计算的组。

注解

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

警告

如果您删除 ldap 标签,用户将受到威胁,作为纯内部地理节点。

您还可以在用户登录之前提前手动生成geonode组。在这种情况下,当用户登录并且映射的LDAP组已经存在时,用户只被添加到GeONODE组。

一定要退房 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=postgresql://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_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 LogsAsh用于集中监控/分析

这个contrib应用程序和GeoNode内部监视应用程序允许管理员配置一个服务,用于将度量数据发送到 集中式服务器 随附的 Logstash .

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

如果管理多个GeoNode实例,则该服务器可以从多个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管理界面设置所有需要的配置。
如果启用,则 地理节点日志 部分将显示 集中式服务器 特点:
Centralized Servers from admin UI

我们再加一个:

Centralized Server set up

这个 Host IP地址和 Port 数字和时间都是必需的 间隔 (默认为3600秒),它定义服务调用轮询(因此应该在哪个时间范围内聚合数据)。

注解

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

其他设置带有默认值:

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

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

  • 队列检查间隔 -->检查数据库中缓存的新消息的内部队列的间隔(秒);

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

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

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

  • Logstash数据库超时 -->“连接”SQLite数据库超时(秒)。

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

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

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

  • 下一次预定交货 -->下一次预定交货的时间戳;

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

Logstash配置

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

logstash配置示例:

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将创建/更新一个celry Periodic Task 它将根据 间隔 配置好的。

您可以在 周期性任务 管理用户界面的部分:

Periodic tasks section

这个 dispatch-metrics-task 任务:

Dispatch metrics task

任务详细信息:

Dispatch metrics task details

警告

当禁用监视是 良好做法 禁用相应的周期性任务。

管理指挥部

除了计划的任务,这个contrib应用程序还提供 dispatch_metrics 命令手动将度量发送到服务器。
显然,所考虑的时间间隔将从最后一次成功交付开始,并在当前时间结束。

启用监视插件时 (USER_ANALYTICS_ENABLEDmonitoring-enabled 设置为 True 和A Geonode LogsAsh用于集中监控/分析 配置好后,Geonode会将度量数据(默认为每小时)发送到外部服务器(Logstash附带)以进行统计数据可视化和分析。

可以使用 manage.py 脚本。不需要任何选项。

$ DJANGO_SETTINGS_MODULE=<your_settings_module> python manage.py dispatch_metrics

执行期间可能引发的异常将报告给GeoNode日志。