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

shreemaan-abhishek 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 d3f198486 fix(attach-consumer-label): always drop client-supplied 
configured headers (#13590)
d3f198486 is described below

commit d3f198486af31518e1bf039fc604d90008f732f5
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Wed Jun 24 17:16:58 2026 +0800

    fix(attach-consumer-label): always drop client-supplied configured headers 
(#13590)
---
 apisix/plugins/attach-consumer-label.lua        | 15 +++--
 docs/en/latest/plugins/attach-consumer-label.md |  2 +-
 docs/zh/latest/plugins/attach-consumer-label.md |  2 +-
 t/plugin/attach-consumer-label.t                | 90 +++++++++++++++++++++++++
 4 files changed, 100 insertions(+), 9 deletions(-)

diff --git a/apisix/plugins/attach-consumer-label.lua 
b/apisix/plugins/attach-consumer-label.lua
index 6d3396a02..d76cbf99b 100644
--- a/apisix/plugins/attach-consumer-label.lua
+++ b/apisix/plugins/attach-consumer-label.lua
@@ -46,20 +46,21 @@ function _M.check_schema(conf)
 end
 
 function _M.before_proxy(conf, ctx)
-    -- check if the consumer is exists in the context
-    if not ctx.consumer then
+    local labels = ctx.consumer and ctx.consumer.labels
+
+    -- no labels to map: just drop client-supplied copies of the configured 
headers
+    if not labels then
+        for header in pairs(conf.headers) do
+            core.request.set_header(ctx, header, nil)
+        end
         return
     end
 
-    local labels = ctx.consumer.labels
     core.log.info("consumer username: ", ctx.consumer.username, " labels: ",
             core.json.delay_encode(labels))
-    if not labels then
-        return
-    end
 
     for header, label_key in pairs(conf.headers) do
-        -- remove leading $ character
+        -- remove leading $ character, set value (nil clears any 
client-supplied copy)
         local label_value = labels[label_key:sub(2)]
         core.request.set_header(ctx, header, label_value)
     end
diff --git a/docs/en/latest/plugins/attach-consumer-label.md 
b/docs/en/latest/plugins/attach-consumer-label.md
index 2f5557d8e..9bfecda01 100644
--- a/docs/en/latest/plugins/attach-consumer-label.md
+++ b/docs/en/latest/plugins/attach-consumer-label.md
@@ -40,7 +40,7 @@ The `attach-consumer-label` Plugin attaches custom 
consumer-related labels, in a
 
 | Name     | Type   | Required | Default | Valid values | Description          
                                                                                
                                                                                
                                                                                
                                                                                
                                                           |
 
|----------|--------|----------|---------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| headers  | object | True     |         |              | Key-value pairs of 
Consumer labels to be attached to request headers, where key is the request 
header name, such as `X-Consumer-Role`, and the value is a reference to the 
custom label key, such as `$role`. Note that the value should always start with 
a dollar sign (`$`). If a referenced Consumer label value is not configured on 
the Consumer, the corresponding header will not be attached to the request. |
+| headers  | object | True     |         |              | Key-value pairs of 
Consumer labels to be attached to request headers, where key is the request 
header name, such as `X-Consumer-Role`, and the value is a reference to the 
custom label key, such as `$role`. Note that the value should always start with 
a dollar sign (`$`). Any client-supplied value of a configured header is always 
removed first, so the Upstream only ever sees the gateway-set value. If a 
referenced Consumer label val [...]
 
 ## Examples
 
diff --git a/docs/zh/latest/plugins/attach-consumer-label.md 
b/docs/zh/latest/plugins/attach-consumer-label.md
index 5981cc737..10fc6d0c1 100644
--- a/docs/zh/latest/plugins/attach-consumer-label.md
+++ b/docs/zh/latest/plugins/attach-consumer-label.md
@@ -40,7 +40,7 @@ description: attach-consumer-label 插件将自定义消费者标签附加到经
 
 | 名称      | 类型   | 必选项 | 默认值 | 有效值 | 描述                                        
                                                                                
                         |
 
|----------|--------|--------|--------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------|
-| headers  | object | 是     |        |        | 
要附加到请求标头的消费者标签键值对,其中键是请求标头名称(例如 `X-Consumer-Role`),值是对消费者标签键的引用(例如 
`$role`)。注意,值必须以美元符号(`$`)开头。如果消费者上未配置被引用的标签,则对应的请求标头将不会被附加。 |
+| headers  | object | 是     |        |        | 
要附加到请求标头的消费者标签键值对,其中键是请求标头名称(例如 `X-Consumer-Role`),值是对消费者标签键的引用(例如 
`$role`)。注意,值必须以美元符号(`$`)开头。客户端传入的同名请求标头会被先行移除,因此上游只会看到网关设置的值。如果消费者上未配置被引用的标签,则对应的请求标头将不会被附加。
 |
 
 ## 示例
 
diff --git a/t/plugin/attach-consumer-label.t b/t/plugin/attach-consumer-label.t
index 615b1cf09..db0ef634a 100644
--- a/t/plugin/attach-consumer-label.t
+++ b/t/plugin/attach-consumer-label.t
@@ -463,3 +463,93 @@ X-Global-Consumer-Company: api7
 X-Global-Consumer-Department: devops
 --- no_error_log
 [error]
+
+
+
+=== TEST 16: add a no-label consumer and a route that echoes upstream-received 
headers
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/consumers',
+                ngx.HTTP_PUT,
+                [[{
+                    "username": "bob"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            local code, body = t('/apisix/admin/consumers/bob/credentials/a',
+                ngx.HTTP_PUT,
+                [[{
+                    "plugins": {
+                        "key-auth": {
+                            "key": "key-bob"
+                        }
+                    }
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            local code, body = t('/apisix/admin/routes/2',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "/print_request_received",
+                    "plugins": {
+                        "key-auth": {},
+                        "attach-consumer-label": {
+                            "headers": {
+                                "X-Consumer-Role": "$role"
+                            }
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    }
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 17: client-supplied configured header is dropped at the upstream when 
the consumer has no labels
+# the upstream body must contain the authenticated consumer marker
+# (x-consumer-username: bob) AND must not contain the client-supplied
+# x-consumer-role, proving it was stripped before proxying upstream
+--- request
+GET /print_request_received
+--- more_headers
+apikey: key-bob
+X-Consumer-Role: admin
+--- response_body_like eval
+qr/(?s)^(?!.*x-consumer-role).*x-consumer-username: bob/
+--- no_error_log
+[error]

Reply via email to