Skip to content

Commit

Permalink
feat(ldap-auth): use lua-resty-ldap instead of lualdap (apache#7590)
Browse files Browse the repository at this point in the history
  • Loading branch information
kingluo authored and Liu-Junlin committed Nov 4, 2022
1 parent 27f4200 commit ed9ab7a
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 19 deletions.
29 changes: 21 additions & 8 deletions apisix/plugins/ldap-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ local ngx = ngx
local ngx_re = require("ngx.re")
local ipairs = ipairs
local consumer_mod = require("apisix.consumer")
local lualdap = require("lualdap")
local ldap = require("resty.ldap")

local lrucache = core.lrucache.new({
ttl = 300, count = 512
Expand All @@ -31,8 +31,9 @@ local schema = {
properties = {
base_dn = { type = "string" },
ldap_uri = { type = "string" },
use_tls = { type = "boolean" },
uid = { type = "string" }
use_tls = { type = "boolean", default = false },
tls_verify = { type = "boolean", default = false },
uid = { type = "string", default = "cn" }
},
required = {"base_dn","ldap_uri"},
}
Expand Down Expand Up @@ -136,11 +137,23 @@ function _M.rewrite(conf, ctx)
end

-- 2. try authenticate the user against the ldap server
local uid = conf.uid or "cn"

local userdn = uid .. "=" .. user.username .. "," .. conf.base_dn
local ld = lualdap.open_simple (conf.ldap_uri, userdn, user.password, conf.use_tls)
if not ld then
local ldap_host, ldap_port = core.utils.parse_addr(conf.ldap_uri)

local userdn = conf.uid .. "=" .. user.username .. "," .. conf.base_dn
local ldapconf = {
timeout = 10000,
start_tls = false,
ldap_host = ldap_host,
ldap_port = ldap_port or 389,
ldaps = conf.use_tls,
tls_verify = conf.tls_verify,
base_dn = conf.base_dn,
attribute = conf.uid,
keepalive = 60000,
}
local res, err = ldap.ldap_authenticate(user.username, user.password, ldapconf)
if not res then
core.log.warn("ldap-auth failed: ", err)
return 401, { message = "Invalid user authorization" }
end

Expand Down
14 changes: 10 additions & 4 deletions ci/pod/docker-compose.plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,19 @@ services:
openldap:
image: bitnami/openldap:2.5.8
environment:
LDAP_ADMIN_USERNAME: amdin
LDAP_ADMIN_PASSWORD: adminpassword
LDAP_USERS: user01,user02
LDAP_PASSWORDS: password1,password2
- LDAP_ADMIN_USERNAME=amdin
- LDAP_ADMIN_PASSWORD=adminpassword
- LDAP_USERS=user01,user02
- LDAP_PASSWORDS=password1,password2
- LDAP_ENABLE_TLS=yes
- LDAP_TLS_CERT_FILE=/certs/localhost_slapd_cert.pem
- LDAP_TLS_KEY_FILE=/certs/localhost_slapd_key.pem
- LDAP_TLS_CA_FILE=/certs/apisix.crt
ports:
- "1389:1389"
- "1636:1636"
volumes:
- ./t/certs:/certs


rocketmq_namesrv:
Expand Down
5 changes: 3 additions & 2 deletions docs/en/latest/plugins/ldap-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The `ldap-auth` Plugin can be used to add LDAP authentication to a Route or a Se

This Plugin works with the Consumer object and the consumers of the API can authenticate with an LDAP server using [basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication).

This Plugin uses [lualdap](https://lualdap.github.io/lualdap/) for connecting with an LDAP server.
This Plugin uses [lua-resty-ldap](https://github.com/api7/lua-resty-ldap) for connecting with an LDAP server.

## Attributes

Expand All @@ -49,7 +49,8 @@ For Route:
|----------|---------|----------|---------|------------------------------------------------------------------------|
| base_dn | string | True | | Base dn of the LDAP server. For example, `ou=users,dc=example,dc=org`. |
| ldap_uri | string | True | | URI of the LDAP server. |
| use_tls | boolean | False | `true` | If set to `true` uses TLS. |
| use_tls | boolean | False | `false` | If set to `true` uses TLS. |
| tls_verify| boolean | False | `false` | Whether to verify the server certificate when `use_tls` is enabled; If set to `true`, you must set `ssl_trusted_certificate` in `config.yaml`, and make sure the host of `ldap_uri` matches the host in server certificate. |
| uid | string | False | `cn` | uid attribute. |

## Enabling the plugin
Expand Down
5 changes: 3 additions & 2 deletions docs/zh/latest/plugins/ldap-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ description: 本篇文档介绍了 Apache APISIX ldap-auth 插件的相关信息

## 描述

`ldap-auth` 插件可用于给路由或服务添加 LDAP 身份认证,该插件使用 [lualdap](https://lualdap.github.io/lualdap/) 连接 LDAP 服务器。
`ldap-auth` 插件可用于给路由或服务添加 LDAP 身份认证,该插件使用 [lua-resty-ldap](https://github.com/api7/lua-resty-ldap) 连接 LDAP 服务器。

该插件需要与 Consumer 一起配合使用,API 的调用方可以使用 [basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) 与 LDAP 服务器进行认证。

Expand All @@ -47,7 +47,8 @@ Route 端:
|----------|---------|----------|---------|------------------------------------------------------------------------|
| base_dn | string || | LDAP 服务器的 dn,例如:`ou=users,dc=example,dc=org`|
| ldap_uri | string || | LDAP 服务器的 URI。 |
| use_tls | boolean || true | 如果设置为 `true` 则表示启用 TLS。 |
| use_tls | boolean || false | 如果设置为 `true` 则表示启用 TLS。 |
| tls_verify| boolean || false | 是否校验 LDAP 服务器的证书。如果设置为 `true`,你必须设置 `config.yaml` 里面的 `ssl_trusted_certificate`,并且确保 `ldap_uri` 里的 host 和服务器证书中的 host 匹配。 |
| uid | string || cn | UID 属性。 |

## 启用插件
Expand Down
3 changes: 2 additions & 1 deletion rockspec/apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ dependencies = {
"net-url = 0.9-1",
"xml2lua = 1.5-2",
"nanoid = 0.1-1",
"lua-resty-mediador = 0.1.2-1"
"lua-resty-mediador = 0.1.2-1",
"lua-resty-ldap = 0.1.0-0"
}

build = {
Expand Down
24 changes: 24 additions & 0 deletions t/certs/localhost_slapd_cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIECDCCAnCgAwIBAgIUc40/PofbLcrqu/2MJMEkYfrxB+4wDQYJKoZIhvcNAQEL
BQAwVjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzEPMA0GA1UEBwwG
Wmh1SGFpMQ8wDQYDVQQKDAZpcmVzdHkxETAPBgNVBAMMCHRlc3QuY29tMB4XDTIy
MDgwMjA1NDI1OFoXDTIzMDgwMjA1NDI1OFowLjESMBAGA1UEAxMJbG9jYWxob3N0
MRgwFgYDVQQKEw9FeGFtcGxlIENvbXBhbnkwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCxE5zfta69uPsQVDiV0OwWHDGxTBYNzmp5zsVwOF3bOH+hyB4M
+qFxPEuH84/Ib4GJdLM67qZth1azHudKy/QGPFkoeFUW1JhB9QGyjh/URwxTy05b
Ce5w7Ee1rMV/GWu6fxMfIE3o5U0XuW1IKQFaZVdNuQlvG4VjL59BfnEF+YXb1QDB
kIpvf59q+UuZgit8CrO1dDYeJ/xO3N9v2CS2u6si9/XWgIwayw67tmb7cbTu/srB
C99w97IMP5/Vkeu6fkg2jTuvCRARzMQJ11krDmtGeYum9SSCdyTLxK1u7w33DuhQ
3HE/PfHJj9QV1MKIeruVjEvawJsRiWQG0Ai7AgMBAAGjdjB0MAwGA1UdEwEB/wQC
MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUDAwegADAdBgNVHQ4E
FgQUcGOrPCoztq5Z7mjgGtaCkPkmDWowHwYDVR0jBBgwFoAUmbUr1fJgcJdG6ZLx
bYMojlFHG7MwDQYJKoZIhvcNAQELBQADggGBABNOTIiLHNQJfyV20UxcyzZ9xTuc
DuMzEexWJ6S33yJTyp5jni0vFaF9wnT1MOtp+Zizz0hQq0d+GvsmBzjkDdipFqUB
Dt4517l4Z/H4n4FV0jhqQhhzcPRWI5H2MNU0Ezno1iCaKD29Kq61fo2qrU7SNDre
RjnGueTW6u+YLj1ss+UK2rTCRX/Nqqz+MrvIift5Kj4c/8sAD3Zn2aXlH0dXSTcX
DaqNDPQvcdlqNMRSJSthLXYBn40Ro6mH7uA+e4aIVn4jyYvyb8qY5LhQPesTcJZw
IEDmIgFEIh0k1YoGvLD6TkMdKPUG536zH+4iZjKpwGwNQ/dTBgn4+5UOqguiYgXd
MP/eeXSCGLAIjQ4+i1ghv1eAlHuHSQ3Dm75icpAL7VHFdoI7I3wqeE5+IyrUXjX0
s1bCjIuwGxgoBBTzv25OijmTmMcLYDp04PR5qSwckvsrrxHr+2ujeqS+AGxzZ4Sk
N1JSJL69zUwfCVdE3mR+6OmmDcuVlB3u+grLFQ==
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions t/certs/localhost_slapd_key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAsROc37Wuvbj7EFQ4ldDsFhwxsUwWDc5qec7FcDhd2zh/ocge
DPqhcTxLh/OPyG+BiXSzOu6mbYdWsx7nSsv0BjxZKHhVFtSYQfUBso4f1EcMU8tO
WwnucOxHtazFfxlrun8THyBN6OVNF7ltSCkBWmVXTbkJbxuFYy+fQX5xBfmF29UA
wZCKb3+favlLmYIrfAqztXQ2Hif8Ttzfb9gktrurIvf11oCMGssOu7Zm+3G07v7K
wQvfcPeyDD+f1ZHrun5INo07rwkQEczECddZKw5rRnmLpvUkgncky8Stbu8N9w7o
UNxxPz3xyY/UFdTCiHq7lYxL2sCbEYlkBtAIuwIDAQABAoIBAGDANpaEzlUbHRJu
8fvpixUJkp0s1V/1yHeFYptOMPn2hMYAcWrmBg+4wgwmKAl742sXOFaazpRJvjVg
TT+w8EP39T8HgHZY8lgXZjYJMZrqtvGRw946Lu3EK+o33DD10sazZ98551e48cZk
qjEjNnoNpQXydBUhFGB9RKakT1zTb8e+ZQdsrE+ZzgM9/xVFRx4gsfNbed/5TMHZ
QbwaqPzQRiS9ScRwvZ+TE20cGQ66qZqR6+JCatc8BpXA9Q6ZmTj61MSl6MMzCuOS
yIGm5J+siPkLV/ki+MAHk59G9iEsTjS1T1l4aQn0kTtdMx9oVCPODY6Jdi8jIaU/
TwGWuQECgYEAxJEg/YKjZGQFhidP64OGi1ochFZxuJFwcZ17DgmZPkiU+vpC8KYl
QpR0r0zN9vqP+71nMMoVJfektXRMP4cy0ebSAbx47X5IfdYUhID+/OAlxbl1O9ah
lGWk90zknVvQKahImtYZqepQEYyetQiDB4gX2bLT+8IIt16ebGC/TyUCgYEA5p3g
Tcj69nxyy4BuGxYuNfTORTCzd9zhURN7325HVBMlhen/f1e+yjV1zth9yLDl5Wyl
99jkVCvy6p83s+1EDKdgOTYrxgD31Y934De/m53U6P/yHeic3z9dIgIAn+qcJqU6
CL28lXEV8jKLNmlR0crWSjtSBDIpA3BWWN834l8CgYAxgcPnVZHFZROnGBue2391
dXqdMhBuReMmGl21yWEZOLqdA478gTv9KtrAk/2D6NN+udNVjHALIfYP5XyWu3xn
NVVLLqbeWeH0H4kHXl3aXrHkvLL0ITiM4ZTM3EbwAwHInCO9K5NHIkaMRPhr6/rk
WLh5Efsl+1aqqGAKN8u3KQKBgFDjcUh3RSdtkSo12ujfR8gfHLaCFYDmVZWFev5s
hNJFgPTOlZJJ6Z6tT6wEnWHmQkzNZg1f4v5vB94piHUwtJynnIWUrZfewQ8EKmzX
wPpJSuOK2paI/3UCmZ0TDLsKpEidzZRBUMMuDh+MgO3N1Sf7uFwDIIpeOap+HZtA
eC6LAoGAFaN/0hr3kBCGGUQ0MKSEw1A4jJntR+Enz5+vJ1F/yW7E3SNp5gHz8sF1
ppt3OZKtZeIoaCapIEr4hRZzzZr2zNHu3tyizscLAdcqKbt2o7OlPK7Z5mhREN8E
F4obLQI+YsAv2aOY2EFTSPq70N2OL45NLsdq3igpKZEIbpUgnwA=
-----END RSA PRIVATE KEY-----
105 changes: 103 additions & 2 deletions t/plugin/ldap-auth.t
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ Authorization: Basic Zm9vOmZvbwo=
--- error_code: 401
--- response_body
{"message":"Invalid user authorization"}
--- error_log
The supplied credential is invalid
Expand Down Expand Up @@ -302,7 +304,7 @@ find consumer user01
ngx.HTTP_GET,
nil,
[[
{"title":"work with route or service object","required":["base_dn","ldap_uri"],"properties":{"base_dn":{"type":"string"},"ldap_uri":{"type":"string"},"use_tls":{"type":"boolean"},"disable":{"type":"boolean"},"uid":{"type":"string"}},"type":"object"}
{"title":"work with route or service object","required":["base_dn","ldap_uri"],"properties":{"base_dn":{"type":"string"},"ldap_uri":{"type":"string"},"use_tls":{"type":"boolean"},"tls_verify":{"type":"boolean"},"disable":{"type":"boolean"},"uid":{"type":"string"}},"type":"object"}
]]
)
ngx.status = code
Expand Down Expand Up @@ -338,8 +340,107 @@ find consumer user01
ngx.HTTP_GET,
nil,
[[
{"title":"work with route or service object","required":["base_dn","ldap_uri"],"properties":{"base_dn":{"type":"string"},"ldap_uri":{"type":"string"},"use_tls":{"type":"boolean"},"disable":{"type":"boolean"},"uid":{"type":"string"}},"type":"object"} ]]
{"title":"work with route or service object","required":["base_dn","ldap_uri"],"properties":{"base_dn":{"type":"string"},"ldap_uri":{"type":"string"},"use_tls":{"type":"boolean"},"tls_verify":{"type":"boolean"},"disable":{"type":"boolean"},"uid":{"type":"string"}},"type":"object"} ]]
)
ngx.status = code
}
}
=== TEST 17: enable ldap-auth with tls
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"ldap-auth": {
"base_dn": "ou=users,dc=example,dc=org",
"ldap_uri": "localhost:1636",
"uid": "cn",
"use_tls": true
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 18: verify
--- request
GET /hello
--- more_headers
Authorization: Basic dXNlcjAxOnBhc3N3b3JkMQ==
--- response_body
hello world
--- error_log
find consumer user01
=== TEST 19: enable ldap-auth with tls, verify CA
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"ldap-auth": {
"base_dn": "ou=users,dc=example,dc=org",
"ldap_uri": "localhost:1636",
"uid": "cn",
"use_tls": true,
"tls_verify": true
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 20: verify
--- request
GET /hello
--- more_headers
Authorization: Basic dXNlcjAxOnBhc3N3b3JkMQ==
--- response_body
hello world
--- error_log
find consumer user01

0 comments on commit ed9ab7a

Please sign in to comment.