You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2022/08/04 11:36:23 UTC

[apisix] branch master updated: feat(ldap-auth): use lua-resty-ldap instead of lualdap (#7590)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c9008145 feat(ldap-auth): use lua-resty-ldap instead of lualdap (#7590)
0c9008145 is described below

commit 0c90081450281a0c2b2d1d345bb946386fbb9b24
Author: jinhua luo <ho...@163.com>
AuthorDate: Thu Aug 4 19:36:15 2022 +0800

    feat(ldap-auth): use lua-resty-ldap instead of lualdap (#7590)
---
 apisix/plugins/ldap-auth.lua        |  29 +++++++---
 ci/pod/docker-compose.plugin.yml    |  14 +++--
 docs/en/latest/plugins/ldap-auth.md |   5 +-
 docs/zh/latest/plugins/ldap-auth.md |   5 +-
 rockspec/apisix-master-0.rockspec   |   3 +-
 t/certs/localhost_slapd_cert.pem    |  24 +++++++++
 t/certs/localhost_slapd_key.pem     |  27 ++++++++++
 t/plugin/ldap-auth.t                | 105 +++++++++++++++++++++++++++++++++++-
 8 files changed, 193 insertions(+), 19 deletions(-)

diff --git a/apisix/plugins/ldap-auth.lua b/apisix/plugins/ldap-auth.lua
index 3fce91141..d155696b6 100644
--- a/apisix/plugins/ldap-auth.lua
+++ b/apisix/plugins/ldap-auth.lua
@@ -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
@@ -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"},
 }
@@ -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
 
diff --git a/ci/pod/docker-compose.plugin.yml b/ci/pod/docker-compose.plugin.yml
index d03508600..226abd7ed 100644
--- a/ci/pod/docker-compose.plugin.yml
+++ b/ci/pod/docker-compose.plugin.yml
@@ -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:
diff --git a/docs/en/latest/plugins/ldap-auth.md b/docs/en/latest/plugins/ldap-auth.md
index 4bc86401d..b9aa130eb 100644
--- a/docs/en/latest/plugins/ldap-auth.md
+++ b/docs/en/latest/plugins/ldap-auth.md
@@ -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
 
@@ -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
diff --git a/docs/zh/latest/plugins/ldap-auth.md b/docs/zh/latest/plugins/ldap-auth.md
index 075e819f6..c27af4a6a 100644
--- a/docs/zh/latest/plugins/ldap-auth.md
+++ b/docs/zh/latest/plugins/ldap-auth.md
@@ -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 服务器进行认证。
 
@@ -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 属性。                                                         |
 
 ## 启用插件
diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec
index e012abd72..2eb266d2c 100644
--- a/rockspec/apisix-master-0.rockspec
+++ b/rockspec/apisix-master-0.rockspec
@@ -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 = {
diff --git a/t/certs/localhost_slapd_cert.pem b/t/certs/localhost_slapd_cert.pem
new file mode 100644
index 000000000..6140ea5f6
--- /dev/null
+++ b/t/certs/localhost_slapd_cert.pem
@@ -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-----
diff --git a/t/certs/localhost_slapd_key.pem b/t/certs/localhost_slapd_key.pem
new file mode 100644
index 000000000..fa33248c6
--- /dev/null
+++ b/t/certs/localhost_slapd_key.pem
@@ -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-----
diff --git a/t/plugin/ldap-auth.t b/t/plugin/ldap-auth.t
index 9ecac330f..4cf5fa92b 100644
--- a/t/plugin/ldap-auth.t
+++ b/t/plugin/ldap-auth.t
@@ -202,6 +202,8 @@ Authorization: Basic Zm9vOmZvbwo=
 --- error_code: 401
 --- response_body
 {"message":"Invalid user authorization"}
+--- error_log
+The supplied credential is invalid
 
 
 
@@ -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
@@ -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