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

shreemaanabhishek 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 5083ad605 feat: auth plugins respond with `www-authenticate` header 
with realm (#12864)
5083ad605 is described below

commit 5083ad605149d2e7364a19be4758828f4b5b33b4
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Thu Jan 8 13:44:28 2026 +0545

    feat: auth plugins respond with `www-authenticate` header with realm 
(#12864)
---
 apisix/plugins/basic-auth.lua        |   8 +-
 apisix/plugins/hmac-auth.lua         |   4 +
 apisix/plugins/jwt-auth.lua          |   3 +
 apisix/plugins/key-auth.lua          |   3 +
 apisix/plugins/ldap-auth.lua         |  11 ++-
 apisix/schema_def.lua                |  15 +++
 docs/en/latest/plugins/basic-auth.md |   1 +
 docs/en/latest/plugins/hmac-auth.md  |   3 +-
 docs/en/latest/plugins/jwt-auth.md   |   1 +
 docs/en/latest/plugins/key-auth.md   |   1 +
 docs/en/latest/plugins/ldap-auth.md  |   1 +
 t/plugin/basic-auth-realm.t          | 159 +++++++++++++++++++++++++++++++
 t/plugin/hmac-auth-realm.t           | 159 +++++++++++++++++++++++++++++++
 t/plugin/jwt-auth-realm.t            | 159 +++++++++++++++++++++++++++++++
 t/plugin/key-auth-realm.t            | 159 +++++++++++++++++++++++++++++++
 t/plugin/ldap-auth-realm.t           | 177 +++++++++++++++++++++++++++++++++++
 16 files changed, 858 insertions(+), 6 deletions(-)

diff --git a/apisix/plugins/basic-auth.lua b/apisix/plugins/basic-auth.lua
index 752ea8133..a6a90d98c 100644
--- a/apisix/plugins/basic-auth.lua
+++ b/apisix/plugins/basic-auth.lua
@@ -32,7 +32,8 @@ local schema = {
         hide_credentials = {
             type = "boolean",
             default = false,
-        }
+        },
+        realm = schema_def.get_realm_schema("basic"),
     },
     anonymous_consumer = schema_def.anonymous_consumer_schema,
 }
@@ -124,7 +125,6 @@ end
 local function find_consumer(ctx)
     local auth_header = core.request.header(ctx, "Authorization")
     if not auth_header then
-        core.response.set_header("WWW-Authenticate", "Basic realm='.'")
         return nil, nil, "Missing authorization in request"
     end
 
@@ -157,15 +157,17 @@ end
 
 
 function _M.rewrite(conf, ctx)
-    local cur_consumer, consumer_conf, err = find_consumer(ctx)
+    local cur_consumer, consumer_conf, err = find_consumer(ctx, conf)
     if not cur_consumer then
         if not conf.anonymous_consumer then
+            core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = err }
         end
         cur_consumer, consumer_conf, err = 
consumer.get_anonymous_consumer(conf.anonymous_consumer)
         if not cur_consumer then
             err = "basic-auth failed to authenticate the request, code: 401. 
error: " .. err
             core.log.error(err)
+            core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = "Invalid user authorization" }
         end
     end
diff --git a/apisix/plugins/hmac-auth.lua b/apisix/plugins/hmac-auth.lua
index 60eca605e..97dda11fe 100644
--- a/apisix/plugins/hmac-auth.lua
+++ b/apisix/plugins/hmac-auth.lua
@@ -63,6 +63,7 @@ local schema = {
             default = false,
         },
         hide_credentials = {type = "boolean", default = false},
+        realm = schema_def.get_realm_schema("hmac"),
         anonymous_consumer = schema_def.anonymous_consumer_schema,
     },
 }
@@ -346,14 +347,17 @@ function _M.rewrite(conf, ctx)
     local cur_consumer, consumers_conf, err = find_consumer(conf, ctx)
     if not cur_consumer then
         if not conf.anonymous_consumer then
+            core.response.set_header("WWW-Authenticate", "hmac realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = err }
         end
         cur_consumer, consumers_conf, err = 
consumer.get_anonymous_consumer(conf.anonymous_consumer)
         if not cur_consumer then
             if auth_utils.is_running_under_multi_auth(ctx) then
+                core.response.set_header("WWW-Authenticate", "hmac realm=\"" 
.. conf.realm .. "\"")
                 return 401, err
             end
             core.log.error(err)
+            core.response.set_header("WWW-Authenticate", "hmac realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = "Invalid user authorization" }
         end
     end
diff --git a/apisix/plugins/jwt-auth.lua b/apisix/plugins/jwt-auth.lua
index 197efc5fa..4c32609bf 100644
--- a/apisix/plugins/jwt-auth.lua
+++ b/apisix/plugins/jwt-auth.lua
@@ -58,6 +58,7 @@ local schema = {
             type = "boolean",
             default = false
         },
+        realm = schema_def.get_realm_schema("jwt"),
         anonymous_consumer = schema_def.anonymous_consumer_schema,
     },
 }
@@ -307,12 +308,14 @@ function _M.rewrite(conf, ctx)
     local consumer, consumer_conf, err = find_consumer(conf, ctx)
     if not consumer then
         if not conf.anonymous_consumer then
+            core.response.set_header("WWW-Authenticate", "Bearer realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = err }
         end
         consumer, consumer_conf, err = 
consumer_mod.get_anonymous_consumer(conf.anonymous_consumer)
         if not consumer then
             err = "jwt-auth failed to authenticate the request, code: 401. 
error: " .. err
             core.log.error(err)
+            core.response.set_header("WWW-Authenticate", "Bearer realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = "Invalid user authorization"}
         end
     end
diff --git a/apisix/plugins/key-auth.lua b/apisix/plugins/key-auth.lua
index 7bef9f83c..020326dce 100644
--- a/apisix/plugins/key-auth.lua
+++ b/apisix/plugins/key-auth.lua
@@ -30,6 +30,7 @@ local schema = {
             type = "string",
             default = "apikey",
         },
+        realm = schema_def.get_realm_schema("key"),
         hide_credentials = {
             type = "boolean",
             default = false,
@@ -104,12 +105,14 @@ function _M.rewrite(conf, ctx)
     local consumer, consumer_conf, err = find_consumer(ctx, conf)
     if not consumer then
         if not conf.anonymous_consumer then
+            core.response.set_header("WWW-Authenticate", "apikey realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = err}
         end
         consumer, consumer_conf, err = 
consumer_mod.get_anonymous_consumer(conf.anonymous_consumer)
         if not consumer then
             err = "key-auth failed to authenticate the request, code: 401. 
error: " .. err
             core.log.error(err)
+            core.response.set_header("WWW-Authenticate", "apikey realm=\"" .. 
conf.realm .. "\"")
             return 401, { message = "Invalid user authorization"}
         end
     end
diff --git a/apisix/plugins/ldap-auth.lua b/apisix/plugins/ldap-auth.lua
index 1d89efef8..30c836742 100644
--- a/apisix/plugins/ldap-auth.lua
+++ b/apisix/plugins/ldap-auth.lua
@@ -19,6 +19,8 @@ local ngx = ngx
 local ngx_re = require("ngx.re")
 local consumer_mod = require("apisix.consumer")
 local ldap = require("resty.ldap")
+local schema_def = require("apisix.schema_def")
+
 
 local schema = {
     type = "object",
@@ -28,7 +30,8 @@ local schema = {
         ldap_uri = { type = "string" },
         use_tls = { type = "boolean", default = false },
         tls_verify = { type = "boolean", default = false },
-        uid = { type = "string", default = "cn" }
+        uid = { type = "string", default = "cn" },
+        realm = schema_def.get_realm_schema("ldap"),
     },
     required = {"base_dn","ldap_uri"},
 }
@@ -106,7 +109,7 @@ function _M.rewrite(conf, ctx)
     -- 1. extract authorization from header
     local auth_header = core.request.header(ctx, "Authorization")
     if not auth_header then
-        core.response.set_header("WWW-Authenticate", "Basic realm='.'")
+        core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
         return 401, { message = "Missing authorization in request" }
     end
 
@@ -117,6 +120,7 @@ function _M.rewrite(conf, ctx)
         else
           core.log.warn("nil user")
         end
+        core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
         return 401, { message = "Invalid authorization in request" }
     end
 
@@ -136,6 +140,7 @@ function _M.rewrite(conf, ctx)
     local res, err = ldap.ldap_authenticate(user.username, user.password, 
ldapconf)
     if not res then
         core.log.warn("ldap-auth failed: ", err)
+        core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
         return 401, { message = "Invalid user authorization" }
     end
 
@@ -144,12 +149,14 @@ function _M.rewrite(conf, ctx)
     -- 3. Retrieve consumer for authorization plugin
     local consumer_conf = consumer_mod.plugin(plugin_name)
     if not consumer_conf then
+        core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
         return 401, { message = "Missing related consumer" }
     end
 
     local consumers = consumer_mod.consumers_kv(plugin_name, consumer_conf, 
"user_dn")
     local consumer = consumers[user_dn]
     if not consumer then
+        core.response.set_header("WWW-Authenticate", "Basic realm=\"" .. 
conf.realm .. "\"")
         return 401, {message = "Invalid user authorization"}
     end
     consumer_mod.attach_consumer(ctx, consumer, consumer_conf)
diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua
index 53b5476db..491265a58 100644
--- a/apisix/schema_def.lua
+++ b/apisix/schema_def.lua
@@ -29,6 +29,21 @@ _M.anonymous_consumer_schema = {
     minLength = "1"
 }
 
+function _M.get_realm_schema(default_val)
+    return {
+        type = "string",
+        -- Pattern: Only allow printable ASCII, but EXCLUDE " and \
+        -- \x20-\x21 (Space and !)
+        -- \x23-\x5B (# through [)
+        -- \x5D-\x7E (] through ~)
+        -- Escaped closing bracket (\x5D) assertion for PCRE compatibility
+        pattern = "^[\x20-\x21\x23-\x5B\\]-\x7E]+$",
+        default = default_val,
+        minLength = 1,
+        maxLength = 128,
+    }
+end
+
 local id_schema = {
     anyOf = {
         {
diff --git a/docs/en/latest/plugins/basic-auth.md 
b/docs/en/latest/plugins/basic-auth.md
index 37e38593c..a82424c3f 100644
--- a/docs/en/latest/plugins/basic-auth.md
+++ b/docs/en/latest/plugins/basic-auth.md
@@ -55,6 +55,7 @@ For Route:
 
|------------------|---------|----------|---------|------------------------------------------------------------------------|
 | hide_credentials | boolean | False    | false   | If true, do not pass the 
authorization request header to Upstream services. |
 | anonymous_consumer | boolean | False    | false | Anonymous Consumer name. 
If configured, allow anonymous users to bypass the authentication. |
+| realm            | string  | False    | basic | The realm to include in the 
`WWW-Authenticate` header when authentication fails. |
 
 ## Examples
 
diff --git a/docs/en/latest/plugins/hmac-auth.md 
b/docs/en/latest/plugins/hmac-auth.md
index 354af2a15..24f741f25 100644
--- a/docs/en/latest/plugins/hmac-auth.md
+++ b/docs/en/latest/plugins/hmac-auth.md
@@ -54,9 +54,10 @@ The following attributes are available for configurations on 
Routes or Services.
 | allowed_algorithms             | array[string]        | False    | 
["hmac-sha1","hmac-sha256","hmac-sha512"] | combination of 
"hmac-sha1","hmac-sha256",and "hmac-sha512" | The list of HMAC algorithms 
allowed.                                                                        
                                                                                
                        |
 | clock_skew            | integer       | False    | 300             |         
        >=1                          | Maximum allowable time difference in 
seconds between the client request's timestamp and APISIX server's current 
time. This helps account for discrepancies in time synchronization between the 
client’s and server’s clocks and protect against replay attacks. The timestamp 
in the Date header (must be in GMT format) will be used for the calculation.    
    |
 | signed_headers        | array[string] | False    |               |           
                                  | The list of HMAC-signed headers that should 
be included in the client request's HMAC signature.  |
-| validate_request_body | boolean       | False    | false         |           
                   | If true, validate the integrity of the request body to 
ensure it has not been tampered with during transmission. Specifically, the 
Plugin creates a SHA-256 base64-encoded digest and compare it to the `Digest` 
header. If the Digest` header is missing or if the digests do not match, the 
validation fails.                          |
+| validate_request_body | boolean       | False    | false         |           
                   | If true, validate the integrity of the request body to 
ensure it has not been tampered with during transmission. Specifically, the 
Plugin creates a SHA-256 base64-encoded digest and compare it to the `Digest` 
header. If the `Digest` header is missing or if the digests do not match, the 
validation fails.                          |
 | hide_credentials | boolean       | False    | false         |                
              | If true, do not pass the authorization request header to 
Upstream services.                        |
 | anonymous_consumer | string    | False    |          |                       
       | Anonymous Consumer name. If configured, allow anonymous users to 
bypass the authentication.                        |
+| realm              | string    | False    | hmac     |                       
       | The realm to include in the `WWW-Authenticate` header when 
authentication fails.                                                           
                                  |
 
 NOTE: `encrypt_fields = {"secret_key"}` is also defined in the schema, which 
means that the field will be stored encrypted in etcd. See [encrypted storage 
fields](../plugin-develop.md#encrypted-storage-fields).
 
diff --git a/docs/en/latest/plugins/jwt-auth.md 
b/docs/en/latest/plugins/jwt-auth.md
index a22b6fbb8..a85d84429 100644
--- a/docs/en/latest/plugins/jwt-auth.md
+++ b/docs/en/latest/plugins/jwt-auth.md
@@ -68,6 +68,7 @@ For Routes or Services:
 | key_claim_name  | string  | False    | key     | The name of the JWT claim 
that contains the user key (corresponds to Consumer's key attribute). |
 | anonymous_consumer | string | False  | false  | Anonymous Consumer name. If 
configured, allow anonymous users to bypass the authentication.   |
 | store_in_ctx     | boolean | False    | false   | Set to true will store the 
JWT payload in the request context (`ctx.jwt_auth_payload`). This allows 
lower-priority plugins that run afterwards on the same request to retrieve and 
use the JWT token. |
+| realm            | string  | False    | jwt     | The realm to include in 
the `WWW-Authenticate` header when authentication fails. |
 
 You can implement `jwt-auth` with [HashiCorp 
Vault](https://www.vaultproject.io/) to store and fetch secrets and RSA keys 
pairs from its [encrypted KV 
engine](https://developer.hashicorp.com/vault/docs/secrets/kv) using the 
[APISIX Secret](../terminology/secret.md) resource.
 
diff --git a/docs/en/latest/plugins/key-auth.md 
b/docs/en/latest/plugins/key-auth.md
index 655eb3e31..8a7d7aa1a 100644
--- a/docs/en/latest/plugins/key-auth.md
+++ b/docs/en/latest/plugins/key-auth.md
@@ -58,6 +58,7 @@ For Route:
 | query  | string | False    | apikey  | The query string to get the key from. 
Lower priority than header.                                                     
                                                                                
                                                                        |
 | hide_credentials   | boolean | False    | false  | If true, do not pass the 
header or query string with key to Upstream services.  |
 | anonymous_consumer | string  | False    | false  | Anonymous Consumer name. 
If configured, allow anonymous users to bypass the authentication.  |
+| realm              | string  | False    | key    | The realm to include in 
the `WWW-Authenticate` header when authentication fails. |
 
 ## Examples
 
diff --git a/docs/en/latest/plugins/ldap-auth.md 
b/docs/en/latest/plugins/ldap-auth.md
index 7e33fc977..95b6884bd 100644
--- a/docs/en/latest/plugins/ldap-auth.md
+++ b/docs/en/latest/plugins/ldap-auth.md
@@ -53,6 +53,7 @@ For Route:
 | 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.                     
                                    |
+| realm    | string  | False    | ldap    | The realm to include in the 
`WWW-Authenticate` header when authentication fails.                 |
 
 ## Enable plugin
 
diff --git a/t/plugin/basic-auth-realm.t b/t/plugin/basic-auth-realm.t
new file mode 100644
index 000000000..ff9ad3968
--- /dev/null
+++ b/t/plugin/basic-auth-realm.t
@@ -0,0 +1,159 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity, default realm
+--- 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": {
+                        "basic-auth": {}
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: verify default realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="basic"
+
+
+
+=== TEST 3: set custom realm
+--- 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": {
+                        "basic-auth": {
+                            "realm": "secure-zone"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 4: verify custom realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="secure-zone"
+
+
+
+=== TEST 5: set anonymous consumer
+--- 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": {
+                        "basic-auth": {
+                            "anonymous_consumer": "missing-consumer"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 6: verify anonymous consumer missing returns realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="basic"
+--- error_log
+failed to get anonymous consumer
diff --git a/t/plugin/hmac-auth-realm.t b/t/plugin/hmac-auth-realm.t
new file mode 100644
index 000000000..34dc822d7
--- /dev/null
+++ b/t/plugin/hmac-auth-realm.t
@@ -0,0 +1,159 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity, default realm
+--- 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": {
+                        "hmac-auth": {}
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: verify default realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: hmac realm="hmac"
+
+
+
+=== TEST 3: set custom realm
+--- 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": {
+                        "hmac-auth": {
+                            "realm": "my-hmac-realm"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 4: verify custom realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: hmac realm="my-hmac-realm"
+
+
+
+=== TEST 5: set anonymous consumer
+--- 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": {
+                        "hmac-auth": {
+                            "anonymous_consumer": "missing-consumer"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 6: verify anonymous consumer missing returns realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: hmac realm="hmac"
+--- error_log
+failed to get anonymous consumer
diff --git a/t/plugin/jwt-auth-realm.t b/t/plugin/jwt-auth-realm.t
new file mode 100644
index 000000000..1bb4c921a
--- /dev/null
+++ b/t/plugin/jwt-auth-realm.t
@@ -0,0 +1,159 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity, default realm
+--- 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": {
+                        "jwt-auth": {}
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: verify default realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Bearer realm="jwt"
+
+
+
+=== TEST 3: set custom realm
+--- 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": {
+                        "jwt-auth": {
+                            "realm": "my-jwt-realm"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 4: verify custom realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Bearer realm="my-jwt-realm"
+
+
+
+=== TEST 5: set anonymous consumer
+--- 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": {
+                        "jwt-auth": {
+                            "anonymous_consumer": "missing-consumer"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 6: verify anonymous consumer missing returns realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Bearer realm="jwt"
+--- error_log
+failed to get anonymous consumer
diff --git a/t/plugin/key-auth-realm.t b/t/plugin/key-auth-realm.t
new file mode 100644
index 000000000..ce3b83d8b
--- /dev/null
+++ b/t/plugin/key-auth-realm.t
@@ -0,0 +1,159 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity, default realm
+--- 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": {
+                        "key-auth": {}
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: verify default realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: apikey realm="key"
+
+
+
+=== TEST 3: set custom realm
+--- 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": {
+                        "key-auth": {
+                            "realm": "my-custom-realm"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 4: verify custom realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: apikey realm="my-custom-realm"
+
+
+
+=== TEST 5: set anonymous consumer
+--- 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": {
+                        "key-auth": {
+                            "anonymous_consumer": "missing-consumer"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 6: verify anonymous consumer missing returns realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: apikey realm="key"
+--- error_log
+failed to get anonymous consumer
diff --git a/t/plugin/ldap-auth-realm.t b/t/plugin/ldap-auth-realm.t
new file mode 100644
index 000000000..63dd698b2
--- /dev/null
+++ b/t/plugin/ldap-auth-realm.t
@@ -0,0 +1,177 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: sanity, default realm
+--- 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": "dc=example,dc=com",
+                            "ldap_uri": "ldap://127.0.0.1:1389";
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 2: verify default realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="ldap"
+
+
+
+=== TEST 3: set custom realm
+--- 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": "dc=example,dc=com",
+                            "ldap_uri": "ldap://127.0.0.1:1389";,
+                            "realm": "my-ldap-realm"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 4: verify custom realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="my-ldap-realm"
+
+
+
+=== TEST 5: ldap auth failure (missing header) returns realm
+--- request
+GET /hello
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="my-ldap-realm"
+
+
+
+=== TEST 6: ldap auth failure (invalid credentials) returns realm
+--- 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": "dc=example,dc=com",
+                            "ldap_uri": "ldap://127.0.0.1:1389";,
+                            "realm": "my-ldap-realm"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 7: verify ldap invalid credentials returns realm
+--- request
+GET /hello
+--- more_headers
+Authorization: Basic dXNlcjp3cm9uZw==
+--- error_code: 401
+--- response_headers
+WWW-Authenticate: Basic realm="my-ldap-realm"
+--- error_log
+ldap-auth failed


Reply via email to