diff --git a/apisix/plugins/jwe-decrypt.lua b/apisix/plugins/jwe-decrypt.lua
index 1ecef6795380..f669eb20d611 100644
--- a/apisix/plugins/jwe-decrypt.lua
+++ b/apisix/plugins/jwe-decrypt.lua
@@ -18,7 +18,6 @@ local core = require("apisix.core")
local consumer_mod = require("apisix.consumer")
local base64 = require("ngx.base64")
local aes = require("resty.aes")
-local ngx = ngx
local sub_str = string.sub
local cipher = aes.cipher(256, "gcm")
@@ -147,24 +146,6 @@ local function jwe_decrypt_with_obj(o, consumer)
end
-local function jwe_encrypt(o, consumer)
- local secret = get_secret(consumer.auth_conf)
- local enc = base64.encode_base64url
-
- local aes_default = aes:new(
- secret,
- nil,
- cipher,
- {iv = o.iv})
-
- local encrypted = aes_default:encrypt(o.plaintext)
-
- o.ciphertext = encrypted[1]
- o.tag = encrypted[2]
- return o.header .. ".." .. enc(o.iv) .. "." .. enc(o.ciphertext) .. "." .. enc(o.tag)
-end
-
-
local function get_consumer(key)
local consumer_conf = consumer_mod.plugin(plugin_name)
if not consumer_conf then
@@ -220,57 +201,4 @@ function _M.rewrite(conf, ctx)
core.request.set_header(ctx, conf.forward_header, plaintext)
end
-
-local function gen_token()
- local args = core.request.get_uri_args()
- if not args or not args.key then
- return core.response.exit(400)
- end
-
- local key = args.key
- local payload = args.payload
- if payload then
- payload = ngx.unescape_uri(payload)
- end
-
- local consumer = get_consumer(key)
- if not consumer then
- return core.response.exit(404)
- end
-
- local iv = args.iv
- if not iv then
- -- TODO: random bytes
- iv = "123456789012"
- end
-
- local obj = {
- iv = iv,
- plaintext = payload,
- header_obj = {
- kid = key,
- alg = "dir",
- enc = "A256GCM",
- },
- }
- obj.header = base64.encode_base64url(core.json.encode(obj.header_obj))
- local jwe_token = jwe_encrypt(obj, consumer)
- if jwe_token then
- return core.response.exit(200, jwe_token)
- end
-
- return core.response.exit(404)
-end
-
-
-function _M.api()
- return {
- {
- methods = { "GET" },
- uri = "/apisix/plugin/jwe/encrypt",
- handler = gen_token,
- }
- }
-end
-
return _M
diff --git a/docs/en/latest/plugins/jwe-decrypt.md b/docs/en/latest/plugins/jwe-decrypt.md
index 709cf8e8d200..02dafc7367a7 100644
--- a/docs/en/latest/plugins/jwe-decrypt.md
+++ b/docs/en/latest/plugins/jwe-decrypt.md
@@ -39,7 +39,7 @@ import TabItem from '@theme/TabItem';
The `jwe-decrypt` Plugin decrypts [JWE](https://datatracker.ietf.org/doc/html/rfc7516) authorization headers in requests sent to APISIX [Routes](../terminology/route.md) or [Services](../terminology/service.md).
-This Plugin adds an endpoint `/apisix/plugin/jwe/encrypt` for JWE encryption. For decryption, the key should be configured in [Consumer](../terminology/consumer.md).
+The decryption key should be configured in [Consumer](../terminology/consumer.md).
## Attributes
@@ -73,28 +73,15 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/
:::
-### Expose JWE Encryption Endpoint and Generate JWE Token
+### Create a Consumer with the Decryption Key
-The following example demonstrates how to expose the JWE encryption endpoint and generate a JWE token.
+The following example demonstrates how to create a Consumer with the decryption key and generate a JWE token for it.
-The `jwe-decrypt` Plugin creates an internal endpoint at `/apisix/plugin/jwe/encrypt` to encrypt JWE. Expose the endpoint with the [public-api](public-api.md) Plugin:
+Create a Consumer with `jwe-decrypt` and configure the decryption key:
-```shell
-curl "http://127.0.0.1:9180/apisix/admin/routes/jwe-encrypt-api" -X PUT \
- -H "X-API-KEY: ${admin_key}" \
- -d '{
- "uri": "/apisix/plugin/jwe/encrypt",
- "plugins": {
- "public-api": {}
- }
- }'
-```
-
-Create a Consumer with `jwe-decrypt` and configure the decryption key:
-
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
@@ -113,7 +100,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-Expose the JWE encryption endpoint and create a Consumer with `jwe-decrypt` Credential:
+Create a Consumer with `jwe-decrypt` Credential:
```yaml title="adc.yaml"
consumers:
@@ -122,20 +109,6 @@ consumers:
jwe-decrypt:
key: jack-key
secret: key-length-should-be-32-chars123
-services:
- - name: jwe-encrypt-api-service
- routes:
- - name: jwe-encrypt-api-route
- uris:
- - /apisix/plugin/jwe/encrypt
- plugins:
- public-api: {}
- upstream:
- type: roundrobin
- nodes:
- - host: httpbin.org
- port: 80
- weight: 1
```
Synchronize the configuration to the gateway:
@@ -148,12 +121,12 @@ adc sync -f adc.yaml
-Create a Consumer with `jwe-decrypt` and expose the JWE encryption endpoint with the `public-api` Plugin:
+Create a Consumer with `jwe-decrypt`:
-```yaml title="jwe-encrypt-api-ic.yaml"
+```yaml title="jwe-consumer-ic.yaml"
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
@@ -167,44 +140,12 @@ spec:
config:
key: jack-key
secret: key-length-should-be-32-chars123
----
-apiVersion: apisix.apache.org/v1alpha1
-kind: PluginConfig
-metadata:
- namespace: aic
- name: jwe-encrypt-api-plugin-config
-spec:
- plugins:
- - name: public-api
- config:
- _meta:
- disable: false
----
-apiVersion: gateway.networking.k8s.io/v1
-kind: HTTPRoute
-metadata:
- namespace: aic
- name: jwe-encrypt-api-route
-spec:
- parentRefs:
- - name: apisix
- rules:
- - matches:
- - path:
- type: Exact
- value: /apisix/plugin/jwe/encrypt
- filters:
- - type: ExtensionRef
- extensionRef:
- group: apisix.apache.org
- kind: PluginConfig
- name: jwe-encrypt-api-plugin-config
```
Apply the configuration to your cluster:
```shell
-kubectl apply -f jwe-encrypt-api-ic.yaml
+kubectl apply -f jwe-consumer-ic.yaml
```
@@ -219,22 +160,23 @@ kubectl apply -f jwe-encrypt-api-ic.yaml
-Send a request to the encryption endpoint with Consumer key to encrypt some sample data in the payload:
+To generate a JWE token for the Consumer, encrypt the payload offline with any AES-256-GCM library, using the Consumer secret as the key. The token structure is:
-```shell
-curl "http://127.0.0.1:9080/apisix/plugin/jwe/encrypt?key=jack-key" \
- --data-urlencode 'payload={"uid":10000,"uname":"test"}' -G
+```text
+base64url(header)..base64url(iv).base64url(ciphertext).base64url(tag)
```
-You should see a response similar to the following, with the JWE encrypted data in the response body:
+where the header is `{"alg":"dir","enc":"A256GCM","kid":""}`. The IV must be unique and randomly generated for every token; never reuse an IV with the same key.
+
+For example, the following token encrypts the payload `{"uid":10000,"uname":"test"}` for the Consumer key `jack-key` with the secret configured above:
```text
-eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..MTIzNDU2Nzg5MDEy.IUFW_q4igO_wvf63i-3VwV0MEetPL9C20tlgcQ.fveViMUi0ijJlQ19D7kDrg
+eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A
```
### Decrypt Data with JWE
-The following example demonstrates how to decrypt the previously generated JWE token.
+The following example demonstrates how to decrypt the JWE token generated above.
Create a Route with `jwe-decrypt` to decrypt the authorization header:
@@ -365,7 +307,7 @@ kubectl apply -f jwe-decrypt-ic.yaml
Send a request to the Route with the JWE encrypted data in the `Authorization` header:
```shell
-curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..MTIzNDU2Nzg5MDEy.IUFW_q4igO_wvf63i-3VwV0MEetPL9C20tlgcQ.fveViMUi0ijJlQ19D7kDrg'
+curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A'
```
You should see a response similar to the following, where the `Authorization` header shows the plaintext of the payload:
diff --git a/docs/zh/latest/plugins/jwe-decrypt.md b/docs/zh/latest/plugins/jwe-decrypt.md
index ba5f412e09dc..eb6fcf9b9cd8 100644
--- a/docs/zh/latest/plugins/jwe-decrypt.md
+++ b/docs/zh/latest/plugins/jwe-decrypt.md
@@ -39,7 +39,7 @@ import TabItem from '@theme/TabItem';
`jwe-decrypt` 插件解密发送到 APISIX [路由](../terminology/route.md)或[服务](../terminology/service.md)的请求中的 [JWE](https://datatracker.ietf.org/doc/html/rfc7516) 授权请求头。
-该插件添加了一个 `/apisix/plugin/jwe/encrypt` 内部端点用于 JWE 加密。解密时,密钥应配置在[消费者](../terminology/consumer.md)中。
+解密密钥应配置在[消费者](../terminology/consumer.md)中。
## 属性
@@ -73,28 +73,15 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/
:::
-### 暴露 JWE 加密端点并生成 JWE 令牌
+### 创建带有解密密钥的消费者
-以下示例演示如何暴露 JWE 加密端点并生成 JWE 令牌。
+以下示例演示如何创建带有解密密钥的消费者,并为其生成 JWE 令牌。
-`jwe-decrypt` 插件在 `/apisix/plugin/jwe/encrypt` 创建一个内部端点用于 JWE 加密。使用 [public-api](public-api.md) 插件暴露该端点:
+创建带有 `jwe-decrypt` 的消费者并配置解密密钥:
-```shell
-curl "http://127.0.0.1:9180/apisix/admin/routes/jwe-encrypt-api" -X PUT \
- -H "X-API-KEY: ${admin_key}" \
- -d '{
- "uri": "/apisix/plugin/jwe/encrypt",
- "plugins": {
- "public-api": {}
- }
- }'
-```
-
-创建带有 `jwe-decrypt` 的消费者并配置解密密钥:
-
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${admin_key}" \
@@ -113,7 +100,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-暴露 JWE 加密端点并创建带有 `jwe-decrypt` 凭证的消费者:
+创建带有 `jwe-decrypt` 凭证的消费者:
```yaml title="adc.yaml"
consumers:
@@ -122,20 +109,6 @@ consumers:
jwe-decrypt:
key: jack-key
secret: key-length-should-be-32-chars123
-services:
- - name: jwe-encrypt-api-service
- routes:
- - name: jwe-encrypt-api-route
- uris:
- - /apisix/plugin/jwe/encrypt
- plugins:
- public-api: {}
- upstream:
- type: roundrobin
- nodes:
- - host: httpbin.org
- port: 80
- weight: 1
```
将配置同步到网关:
@@ -148,12 +121,12 @@ adc sync -f adc.yaml
-创建带有 `jwe-decrypt` 的消费者并使用 `public-api` 插件暴露 JWE 加密端点:
+创建带有 `jwe-decrypt` 的消费者:
-```yaml title="jwe-encrypt-api-ic.yaml"
+```yaml title="jwe-consumer-ic.yaml"
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
@@ -167,44 +140,12 @@ spec:
config:
key: jack-key
secret: key-length-should-be-32-chars123
----
-apiVersion: apisix.apache.org/v1alpha1
-kind: PluginConfig
-metadata:
- namespace: aic
- name: jwe-encrypt-api-plugin-config
-spec:
- plugins:
- - name: public-api
- config:
- _meta:
- disable: false
----
-apiVersion: gateway.networking.k8s.io/v1
-kind: HTTPRoute
-metadata:
- namespace: aic
- name: jwe-encrypt-api-route
-spec:
- parentRefs:
- - name: apisix
- rules:
- - matches:
- - path:
- type: Exact
- value: /apisix/plugin/jwe/encrypt
- filters:
- - type: ExtensionRef
- extensionRef:
- group: apisix.apache.org
- kind: PluginConfig
- name: jwe-encrypt-api-plugin-config
```
将配置应用到集群:
```shell
-kubectl apply -f jwe-encrypt-api-ic.yaml
+kubectl apply -f jwe-consumer-ic.yaml
```
@@ -219,22 +160,23 @@ kubectl apply -f jwe-encrypt-api-ic.yaml
-向加密端点发送请求,使用消费者密钥加密 payload 中的示例数据:
+要为消费者生成 JWE 令牌,可使用任意 AES-256-GCM 库离线加密 payload,加密密钥为消费者的 secret。令牌结构如下:
-```shell
-curl "http://127.0.0.1:9080/apisix/plugin/jwe/encrypt?key=jack-key" \
- --data-urlencode 'payload={"uid":10000,"uname":"test"}' -G
+```text
+base64url(header)..base64url(iv).base64url(ciphertext).base64url(tag)
```
-你应该看到类似以下的响应,响应体中包含 JWE 加密数据:
+其中 header 为 `{"alg":"dir","enc":"A256GCM","kid":""}`。每个令牌的 IV 必须唯一且随机生成,切勿在同一密钥下复用 IV。
+
+例如,以下令牌使用上面配置的 secret,为消费者密钥 `jack-key` 加密了 payload `{"uid":10000,"uname":"test"}`:
```text
-eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..MTIzNDU2Nzg5MDEy.IUFW_q4igO_wvf63i-3VwV0MEetPL9C20tlgcQ.fveViMUi0ijJlQ19D7kDrg
+eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A
```
### 使用 JWE 解密数据
-以下示例演示如何解密上述生成的 JWE 令牌。
+以下示例演示如何解密上面生成的 JWE 令牌。
创建带有 `jwe-decrypt` 的路由以解密授权请求头:
@@ -365,7 +307,7 @@ kubectl apply -f jwe-decrypt-ic.yaml
在 `Authorization` 请求头中携带 JWE 加密数据向路由发送请求:
```shell
-curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..MTIzNDU2Nzg5MDEy.IUFW_q4igO_wvf63i-3VwV0MEetPL9C20tlgcQ.fveViMUi0ijJlQ19D7kDrg'
+curl "http://127.0.0.1:9080/anything/jwe" -H 'Authorization: eyJraWQiOiJqYWNrLWtleSIsImFsZyI6ImRpciIsImVuYyI6IkEyNTZHQ00ifQ..vi29KBCQKcVmPwTT.VToyPMFbq-ZY05MIpntP1N3AmYeq3zELQ0B6iQ.vuTPG2ODc-DjUTjNCzfA2A'
```
你应该看到类似以下的响应,其中 `Authorization` 请求头显示了 payload 的明文:
diff --git a/t/plugin/jwe-decrypt.t b/t/plugin/jwe-decrypt.t
index b606f6dd5234..1d72e86aafba 100644
--- a/t/plugin/jwe-decrypt.t
+++ b/t/plugin/jwe-decrypt.t
@@ -242,74 +242,7 @@ passed
-=== TEST 9: create public API route (jwe-decrypt sign)
---- config
- location /t {
- content_by_lua_block {
- local t = require("lib.test_admin").test
- local code, body = t('/apisix/admin/routes/2',
- ngx.HTTP_PUT,
- [[{
- "plugins": {
- "public-api": {}
- },
- "uri": "/apisix/plugin/jwe/encrypt"
- }]]
- )
-
- if code >= 300 then
- ngx.status = code
- end
- ngx.say(body)
- }
- }
---- response_body
-passed
---- no_error_log
-12345678901234567890123456789012
-
-
-
-=== TEST 10: sign / verify in argument
---- config
- location /t {
- content_by_lua_block {
- local t = require("lib.test_admin").test
- local code, err, token = t('/apisix/plugin/jwe/encrypt?key=user-key&payload=hello',
- ngx.HTTP_GET
- )
-
- if code > 200 then
- ngx.status = code
- ngx.say(err)
- return
- end
-
- code, err, body = t('/hello',
- ngx.HTTP_GET,
- nil,
- nil,
- { Authorization = token }
- )
-
- ngx.print(body)
- }
- }
---- response_body
-hello world
---- no_error_log
-12345678901234567890123456789012
-
-
-
-=== TEST 11: test for unsupported method
---- request
-PATCH /apisix/plugin/jwe/encrypt?key=user-key
---- error_code: 404
-
-
-
-=== TEST 12: verify, missing token
+=== TEST 9: verify, missing token
--- request
GET /hello
--- error_code: 403
@@ -318,7 +251,7 @@ GET /hello
-=== TEST 13: verify: invalid JWE token
+=== TEST 10: verify: invalid JWE token
--- request
GET /hello
--- more_headers
@@ -329,7 +262,7 @@ Authorization: invalid-eyJhbGciOiJkaXIiLCJraWQiOiJ1c2VyLWtleSIsImVuYyI6IkEyNTZHQ
-=== TEST 14: verify (in header)
+=== TEST 11: verify (in header)
--- request
GET /hello
--- more_headers
@@ -339,7 +272,7 @@ hello world
-=== TEST 15: verify (in header without Bearer)
+=== TEST 12: verify (in header without Bearer)
--- request
GET /hello
--- more_headers
@@ -349,7 +282,7 @@ hello world
-=== TEST 16: verify (header with bearer)
+=== TEST 13: verify (header with bearer)
--- request
GET /hello
--- more_headers
@@ -359,7 +292,7 @@ hello world
-=== TEST 17: verify (invalid bearer token)
+=== TEST 14: verify (invalid bearer token)
--- request
GET /hello
--- more_headers
@@ -370,7 +303,7 @@ Authorization: bearer invalid-eyJhbGciOiJkaXIiLCJraWQiOiJ1c2VyLWtleSIsImVuYyI6Ik
-=== TEST 18: delete a exist consumer
+=== TEST 15: delete a exist consumer
--- config
location /t {
content_by_lua_block {
@@ -407,8 +340,14 @@ Authorization: bearer invalid-eyJhbGciOiJkaXIiLCJraWQiOiJ1c2VyLWtleSIsImVuYyI6Ik
ngx.HTTP_DELETE)
ngx.say("code: ", code < 300, " body: ", body)
- code, body = t('/apisix/plugin/jwe/encrypt?key=chen-key&payload=hello',
- ngx.HTTP_GET)
+ -- the remaining consumer can still be verified
+ local chen_token = "eyJhbGciOiJkaXIiLCJraWQiOiJjaGVuLWtleSIsImVuYyI6IkEyNTZHQ00ifQ"
+ .. "..MTIzNDU2Nzg5MDEy.ar0vE2I.AOndbhR7J1e2oM3N2c-KYQ"
+ code, body = t('/hello',
+ ngx.HTTP_GET,
+ nil,
+ nil,
+ { Authorization = chen_token })
ngx.say("code: ", code < 300, " body: ", body)
}
}
@@ -419,10 +358,11 @@ code: true body: passed
code: true body: passed
--- no_error_log
12345678901234567890123456789012
+12345678901234567890123456789021
-=== TEST 19: add consumer with username and plugins with base64 secret
+=== TEST 16: add consumer with username and plugins with base64 secret
--- config
location /t {
content_by_lua_block {
@@ -454,7 +394,7 @@ fo4XKdZ1xSrIZyms4q2BwPrW5lMpls9qqy5tiAk2esc=
-=== TEST 20: enable jwt decrypt plugin with base64 secret
+=== TEST 17: enable jwt decrypt plugin with base64 secret
--- config
location /t {
content_by_lua_block {
@@ -490,69 +430,7 @@ fo4XKdZ1xSrIZyms4q2BwPrW5lMpls9qqy5tiAk2esc=
-=== TEST 21: create public API route (jwe-decrypt sign)
---- config
- location /t {
- content_by_lua_block {
- local t = require("lib.test_admin").test
- local code, body = t('/apisix/admin/routes/2',
- ngx.HTTP_PUT,
- [[{
- "plugins": {
- "public-api": {}
- },
- "uri": "/apisix/plugin/jwe/encrypt"
- }]]
- )
-
- if code >= 300 then
- ngx.status = code
- end
- ngx.say(body)
- }
- }
---- response_body
-passed
---- no_error_log
-fo4XKdZ1xSrIZyms4q2BwPrW5lMpls9qqy5tiAk2esc=
-
-
-
-=== TEST 22: sign / verify in argument
---- config
- location /t {
- content_by_lua_block {
- local t = require("lib.test_admin").test
- local code, err, token = t('/apisix/plugin/jwe/encrypt?key=user-key&payload=hello',
- ngx.HTTP_GET
- )
-
- if code > 200 then
- ngx.status = code
- ngx.say(err)
- return
- end
-
- ngx.log(ngx.WARN, "dibag: ", token)
-
- code, err, body = t('/hello',
- ngx.HTTP_GET,
- nil,
- nil,
- { Authorization = token }
- )
-
- ngx.print(body)
- }
- }
---- response_body
-hello world
---- no_error_log
-fo4XKdZ1xSrIZyms4q2BwPrW5lMpls9qqy5tiAk2esc=
-
-
-
-=== TEST 23: verify (in header)
+=== TEST 18: verify (in header)
--- request
GET /hello
--- more_headers
@@ -564,7 +442,7 @@ fo4XKdZ1xSrIZyms4q2BwPrW5lMpls9qqy5tiAk2esc=
-=== TEST 24: verify (in header without Bearer)
+=== TEST 19: verify (in header without Bearer)
--- request
GET /hello
--- more_headers
@@ -574,7 +452,7 @@ hello world
-=== TEST 25: enable jwt decrypt plugin with test upstream route
+=== TEST 20: enable jwt decrypt plugin with test upstream route
--- config
location /t {
content_by_lua_block {
@@ -610,7 +488,7 @@ fo4XKdZ1xSrIZyms4q2BwPrW5lMpls9qqy5tiAk2esc=
-=== TEST 26: verify in upstream header
+=== TEST 21: verify in upstream header
--- request
GET /headers
--- more_headers