跳到主要内容

ldap-auth-advanced

ldap-auth-advanced 插件对接 OpenLDAP、Active Directory 等 LDAP 目录完成客户端认证,并可把认证到的目录用户映射为消费者(Consumer)

插件采用「先检索、后绑定」的方式解析用户:先在 base_dn 下检索 attribute 与客户端提供的用户名匹配的条目,再用客户端提供的密码以该条目执行绑定。由于用户的可分辨名称(DN)是检索出来的而非拼接出来的,目录结构无需写进网关配置,用户也可以位于目录树的不同层级。

consumer_required 启用时(默认启用),插件会继续查找凭据中记录了该 DN 的消费者。匹配成功后,网关会在把请求转发到上游之前加上 X-Consumer-UsernameX-Credential-Identifier 等请求头,因此消费者级插件、限流和用量统计对 LDAP 认证的流量与其它身份一视同仁。把 consumer_required 设为 false 则只对接目录完成认证,不要求存在对应的消费者。

自 API7 企业版 3.10.5 起可用。

信息

插件从 Authorization 请求头读取凭据;当 Proxy-Authorization 携带可用凭据时优先使用后者。方案名由 header_type 决定:默认值 ldap 对应 Authorization: ldap <base64(username:password)>;取值 basic 时使用标准的 Authorization: Basic <base64(username:password)>,因此已有的 HTTP Basic 客户端无需改动即可认证。

示例

以下示例演示了如何在不同场景下使用 ldap-auth-advanced 插件。

前置条件

以下示例假设有一个可通过 192.168.1.10:389 访问的 LDAP 目录,用户条目位于 ou=users,dc=example,dc=org 下,其中一个用户的 uidjohndoe、密码为 john-secret,检索时以 cn=admin,dc=example,dc=org 身份绑定。请根据你自己的目录调整这些取值。

对接 LDAP 目录完成认证

以下示例演示了如何把 consumer_required 设为 false,只对接 LDAP 目录完成客户端认证,而不映射到消费者。

创建一个配置了 ldap-auth-advanced 的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldap-auth-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:389",
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret",
"consumer_required": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

使用正确的凭据验证

用目录用户的凭据向该路由发送请求,凭据经 base64 编码后以 ldap 方案携带:

curl -i "http://127.0.0.1:9080/anything" \
-H "Authorization: ldap $(printf '%s' 'johndoe:john-secret' | base64)"

应当收到 HTTP/1.1 200 OK 响应。

使用错误的凭据验证

用错误的密码向该路由发送请求:

curl -i "http://127.0.0.1:9080/anything" \
-H "Authorization: ldap $(printf '%s' 'johndoe:wrong-password' | base64)"

应当收到 HTTP/1.1 401 Unauthorized 响应:

WWW-Authenticate: ldap realm="ldap"
{"message":"Authorization required"}

不携带凭据验证

不携带任何凭据向该路由发送请求:

curl -i "http://127.0.0.1:9080/anything"

应当收到 HTTP/1.1 401 Unauthorized 响应。

把 LDAP 用户映射为消费者

以下示例演示了如何把目录用户映射为消费者,从而让消费者级的配置对其流量生效。消费者的凭据中记录用户的完整 DN,也就是插件通过目录检索解析出来的那个值。

信息

ldap-auth-advanced 类型的消费者凭据通过 Admin API 或 Dashboard 创建。ADC 与 Ingress Controller 目前只支持 key-authbasic-authjwt-authhmac-auth 类型的凭据。

创建消费者 johndoe

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "johndoe"
}'

为该消费者创建 ldap-auth-advanced 凭据,记录目录条目的 DN:

curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-ldap-auth",
"plugins": {
"ldap-auth-advanced": {
"user_dn": "uid=johndoe,ou=users,dc=example,dc=org"
}
}
}'

创建一个配置了 ldap-auth-advanced 的路由,consumer_required 保持默认值 true

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldap-auth-consumer-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:389",
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

用目录用户的凭据向该路由发送请求:

curl -i "http://127.0.0.1:9080/anything" \
-H "Authorization: ldap $(printf '%s' 'johndoe:john-secret' | base64)"

应当收到 HTTP/1.1 200 OK 响应,上游会看到消费者相关的请求头:

{
"headers": {
"X-Consumer-Username": "johndoe",
"X-Credential-Identifier": "cred-john-ldap-auth",
...
},
...
}

如果目录用户认证成功,但其 DN 没有记录在任何消费者凭据中,则会收到 HTTP/1.1 401 Unauthorized 响应。

接受 HTTP Basic 认证方案

以下示例演示了如何接受标准 HTTP Basic 方案而非 ldap 方案的凭据,从而让已有的 Basic 客户端无需改动即可使用。

在路由上把 header_type 设为 basic

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldap-auth-basic-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:389",
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret",
"header_type": "basic",
"consumer_required": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

用普通的 Basic 凭据发送请求:

curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-secret

应当收到 HTTP/1.1 200 OK 响应。此时未认证请求收到的挑战头也变为 Basic 方案:

WWW-Authenticate: Basic realm="ldap"

通过 TLS 连接目录

以下示例演示了如何通过 LDAPS 访问目录。设置 use_ldaps 并把 ldap_uri 指向 LDAPS 端口;省略端口时,启用 LDAPS 使用 636,否则使用 389。若要在 389 端口上把明文连接升级为 TLS,改用 use_starttls。这两个选项互斥。

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldaps-auth-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:636",
"use_ldaps": true,
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret",
"consumer_required": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

证书校验由 ssl_verify 控制,默认开启。建议保持开启,并确保网关信任签发目录证书的 CA。