diff --git a/apisix/plugins/jwt-auth.lua b/apisix/plugins/jwt-auth.lua index 9fdc7a9b5b18..740efcdc6b4e 100644 --- a/apisix/plugins/jwt-auth.lua +++ b/apisix/plugins/jwt-auth.lua @@ -23,13 +23,11 @@ local new_tab = require ("table.new") local ngx_encode_base64 = ngx.encode_base64 local ngx_decode_base64 = ngx.decode_base64 local ngx = ngx -local ngx_time = ngx.time local sub_str = string.sub local table_insert = table.insert local table_concat = table.concat local ngx_re_gmatch = ngx.re.gmatch local plugin_name = "jwt-auth" -local pcall = pcall local schema = { @@ -90,17 +88,16 @@ local consumer_schema = { { properties = { public_key = {type = "string"}, - private_key= {type = "string"}, algorithm = { enum = {"RS256", "ES256"}, }, }, - required = {"public_key", "private_key"}, + required = {"public_key"}, }, } } }, - encrypt_fields = {"secret", "private_key"}, + encrypt_fields = {"secret"}, required = {"key"}, } @@ -137,17 +134,6 @@ function _M.check_schema(conf, schema_type) end end - if conf.algorithm == "RS256" or conf.algorithm == "ES256" then - -- Possible options are a) public key is missing - -- b) private key is missing - if not conf.public_key then - return false, "missing valid public key" - end - if not conf.private_key then - return false, "missing valid private key" - end - end - return true end @@ -230,106 +216,12 @@ local function get_secret(conf) return secret end - -local function get_rsa_or_ecdsa_keypair(conf) - local public_key = conf.public_key - local private_key = conf.private_key - - if public_key and private_key then - return public_key, private_key - elseif public_key and not private_key then - return nil, nil, "missing private key" - elseif not public_key and private_key then - return nil, nil, "missing public key" - else - return nil, nil, "public and private keys are missing" - end -end - - -local function get_real_payload(key, auth_conf, payload) - local real_payload = { - key = key, - exp = ngx_time() + auth_conf.exp - } - if payload then - local extra_payload = core.json.decode(payload) - core.table.merge(extra_payload, real_payload) - return extra_payload - end - return real_payload -end - - -local function sign_jwt_with_HS(key, consumer, payload) - local auth_secret, err = get_secret(consumer.auth_conf) - if not auth_secret then - core.log.error("failed to sign jwt, err: ", err) - core.response.exit(503, "failed to sign jwt") - end - local ok, jwt_token = pcall(jwt.sign, _M, - auth_secret, - { - header = { - typ = "JWT", - alg = consumer.auth_conf.algorithm - }, - payload = get_real_payload(key, consumer.auth_conf, payload) - } - ) - if not ok then - core.log.warn("failed to sign jwt, err: ", jwt_token.reason) - core.response.exit(500, "failed to sign jwt") - end - return jwt_token -end - - -local function sign_jwt_with_RS256_ES256(key, consumer, payload) - local public_key, private_key, err = get_rsa_or_ecdsa_keypair( - consumer.auth_conf - ) - if not public_key then - core.log.error("failed to sign jwt, err: ", err) - core.response.exit(503, "failed to sign jwt") - end - - local ok, jwt_token = pcall(jwt.sign, _M, - private_key, - { - header = { - typ = "JWT", - alg = consumer.auth_conf.algorithm, - x5c = { - public_key, - } - }, - payload = get_real_payload(key, consumer.auth_conf, payload) - } - ) - if not ok then - core.log.warn("failed to sign jwt, err: ", jwt_token.reason) - core.response.exit(500, "failed to sign jwt") - end - return jwt_token -end - --- introducing method_only flag (returns respective signing method) to save http API calls. -local function algorithm_handler(consumer, method_only) - if not consumer.auth_conf.algorithm or consumer.auth_conf.algorithm == "HS256" - or consumer.auth_conf.algorithm == "HS512" then - if method_only then - return sign_jwt_with_HS - end - - return get_secret(consumer.auth_conf) - elseif consumer.auth_conf.algorithm == "RS256" or consumer.auth_conf.algorithm == "ES256" then - if method_only then - return sign_jwt_with_RS256_ES256 - end - - local public_key, _, err = get_rsa_or_ecdsa_keypair(consumer.auth_conf) - return public_key, err +local function get_auth_secret(auth_conf) + if not auth_conf.algorithm or auth_conf.algorithm == "HS256" + or auth_conf.algorithm == "HS512" then + return get_secret(auth_conf) + elseif auth_conf.algorithm == "RS256" or auth_conf.algorithm == "ES256" then + return auth_conf.public_key end end @@ -366,7 +258,7 @@ function _M.rewrite(conf, ctx) end core.log.info("consumer: ", core.json.delay_encode(consumer)) - local auth_secret, err = algorithm_handler(consumer) + local auth_secret, err = get_auth_secret(consumer.auth_conf) if not auth_secret then core.log.error("failed to retrieve secrets, err: ", err) return 503, {message = "failed to verify jwt"} @@ -387,52 +279,4 @@ function _M.rewrite(conf, ctx) 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_conf = consumer_mod.plugin(plugin_name) - if not consumer_conf then - return core.response.exit(404) - end - - local consumers = consumer_mod.consumers_kv(plugin_name, consumer_conf, "key") - - core.log.info("consumers: ", core.json.delay_encode(consumers)) - local consumer = consumers[key] - if not consumer then - return core.response.exit(404) - end - - core.log.info("consumer: ", core.json.delay_encode(consumer)) - - local sign_handler = algorithm_handler(consumer, true) - local jwt_token = sign_handler(key, consumer, payload) - if jwt_token then - return core.response.exit(200, jwt_token) - end - - return core.response.exit(404) -end - - -function _M.api() - return { - { - methods = {"GET"}, - uri = "/apisix/plugin/jwt/sign", - handler = gen_token, - } - } -end - - return _M diff --git a/docs/en/latest/plugin-develop.md b/docs/en/latest/plugin-develop.md index ff9cfae79a0f..4d0c154c8c7d 100644 --- a/docs/en/latest/plugin-develop.md +++ b/docs/en/latest/plugin-develop.md @@ -439,19 +439,20 @@ end ## register public API -A plugin can register API which exposes to the public. Take jwt-auth plugin as an example, this plugin registers `GET /apisix/plugin/jwt/sign` to allow client to sign its key: +A plugin can register API which exposes to the public. Take batch-requests plugin as an example, this plugin registers `POST /apisix/batch-requests` to allow developers to group multiple API requests into a single HTTP request/response cycle: ```lua -local function gen_token() - --... +function batch_requests() + -- ... end function _M.api() + -- ... return { { - methods = {"GET"}, - uri = "/apisix/plugin/jwt/sign", - handler = gen_token, + methods = {"POST"}, + uri = "/apisix/batch-requests", + handler = batch_requests, } } end diff --git a/docs/en/latest/plugins/jwt-auth.md b/docs/en/latest/plugins/jwt-auth.md index e44fd58a5880..a3522efe730a 100644 --- a/docs/en/latest/plugins/jwt-auth.md +++ b/docs/en/latest/plugins/jwt-auth.md @@ -43,13 +43,12 @@ For Consumer: | key | string | True | | | Unique key for a Consumer. | | secret | string | False | | | The encryption key. If unspecified, auto generated in the background. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | | public_key | string | True if `RS256` or `ES256` is set for the `algorithm` attribute. | | | RSA or ECDSA public key. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | -| private_key | string | True if `RS256` or `ES256` is set for the `algorithm` attribute. | | | RSA or ECDSA private key. This field supports saving the value in Secret Manager using the [APISIX Secret](../terminology/secret.md) resource. | | algorithm | string | False | "HS256" | ["HS256", "HS512", "RS256", "ES256"] | Encryption algorithm. | | exp | integer | False | 86400 | [1,...] | Expiry time of the token in seconds. | | base64_secret | boolean | False | false | | Set to true if the secret is base64 encoded. | | lifetime_grace_period | integer | False | 0 | [0,...] | Define the leeway in seconds to account for clock skew between the server that generated the jwt and the server validating it. Value should be zero (0) or a positive integer. | -NOTE: `encrypt_fields = {"secret", "private_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). +NOTE: `encrypt_fields = {"secret"}` 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). For Route: @@ -62,16 +61,6 @@ For Route: 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. -## API - -This Plugin adds `/apisix/plugin/jwt/sign` as an endpoint. - -:::note - -You may need to use the [public-api](public-api.md) plugin to expose this endpoint. - -::: - ## Enable Plugin To enable the Plugin, you have to create a Consumer object with the JWT token and configure your Route to use JWT authentication. @@ -102,7 +91,7 @@ curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X :::note -The `jwt-auth` Plugin uses the HS256 algorithm by default. To use the RS256 algorithm, you can configure the public key and private key and specify the algorithm: +The `jwt-auth` Plugin uses the HS256 algorithm by default. To use the RS256 algorithm, you can configure the public key and specify the algorithm: ```shell curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X PUT -d ' @@ -112,7 +101,6 @@ curl http://127.0.0.1:9180/apisix/admin/consumers -H "X-API-KEY: $admin_key" -X "jwt-auth": { "key": "user-key", "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----", - "private_key": "-----BEGIN RSA PRIVATE KEY-----\n……\n-----END RSA PRIVATE KEY-----", "algorithm": "RS256" } } @@ -148,53 +136,15 @@ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H "X-API-KEY: $admin_key" -X P ## Example usage -You need to first setup a Route for an API that signs the token using the [public-api](public-api.md) Plugin: - -```shell -curl http://127.0.0.1:9180/apisix/admin/routes/jas -H "X-API-KEY: $admin_key" -X PUT -d ' -{ - "uri": "/apisix/plugin/jwt/sign", - "plugins": { - "public-api": {} - } -}' -``` - -Now, we can get a token: - -- Without extension payload: +You need first to issue a JWT token using some tool such as [JWT.io's debugger](https://jwt.io/#debugger-io) or a programming language. -```shell -curl http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i -``` - -``` -HTTP/1.1 200 OK -Date: Wed, 24 Jul 2019 10:33:31 GMT -Content-Type: text/plain -Transfer-Encoding: chunked -Connection: keep-alive -Server: APISIX web server - -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMX0.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -``` - -- With extension payload: +:::note -```shell -curl -G --data-urlencode 'payload={"uid":10000,"uname":"test"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i -``` +When you are issuing a JWT token, you have to update the payload with `key` matching the credential key you would like to use; and `exp` or `nbf` in UNIX timestamp. -``` -HTTP/1.1 200 OK -Date: Wed, 21 Apr 2021 06:43:59 GMT -Content-Type: text/plain; charset=utf-8 -Transfer-Encoding: chunked -Connection: keep-alive -Server: APISIX/2.4 +e.g. payload=`{"key": "user-key", "exp": 1727274983}` -eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmFtZSI6InRlc3QiLCJ1aWQiOjEwMDAwLCJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTYxOTA3MzgzOX0.jI9-Rpz1gc3u8Y6lZy8I43RXyCu0nSHANCvfn0YZUCY -``` +::: You can now use this token while making requests: diff --git a/docs/en/latest/plugins/public-api.md b/docs/en/latest/plugins/public-api.md index d55131992f0d..6d1034119cd7 100644 --- a/docs/en/latest/plugins/public-api.md +++ b/docs/en/latest/plugins/public-api.md @@ -30,7 +30,7 @@ description: The public-api is used for exposing an API endpoint through a gener The `public-api` is used for exposing an API endpoint through a general HTTP API router. -When you are using custom Plugins, you can use the `public-api` Plugin to define a fixed, public API for a particular functionality. For example, you can create a public API endpoint `/apisix/plugin/jwt/sign` for JWT authentication using the [jwt-auth](./jwt-auth.md) Plugin. +When you are using custom Plugins, you can use the `public-api` Plugin to define a fixed, public API for a particular functionality. For example, you can create a public API endpoint `/apisix/batch-requests` for grouping multiple API requests in one request using the [batch-requests](./batch-requests.md) Plugin. :::note @@ -46,7 +46,7 @@ The public API added in a custom Plugin is not exposed by default and the user s ## Example usage -The example below uses the [jwt-auth](./jwt-auth.md) Plugin and the [key-auth](./key-auth.md) Plugin along with the `public-api` Plugin. Refer to their documentation for it configuration. This step is omitted below and only explains the configuration of the `public-api` Plugin. +The example below uses the [batch-requests](./batch-requests.md) Plugin and the [key-auth](./key-auth.md) Plugin along with the `public-api` Plugin. Refer to their documentation for its configuration. This step is omitted below and only explains the configuration of the `public-api` Plugin. ### Basic usage @@ -57,17 +57,66 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r1' \ -H 'X-API-KEY: ' \ -H 'Content-Type: application/json' \ -d '{ - "uri": "/apisix/plugin/jwt/sign", - "plugins": { + "uri": "/apisix/batch-requests", + "plugins": { "public-api": {} } }' ``` -Now, if you make a request to the configured URI, you will receive a JWT response: +Now, if you make a request to the configured URI, you will receive a batch-requests response: ```shell -curl 'http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key' +curl --location --request POST 'http://127.0.0.1:9080/apisix/batch-requests' \ +--header 'Content-Type: application/json' \ +--data '{ + "headers": { + "Content-Type": "application/json", + "admin-jwt":"xxxx" + }, + "timeout": 500, + "pipeline": [ + { + "method": "POST", + "path": "/community.GiftSrv/GetGifts", + "body": "test" + }, + { + "method": "POST", + "path": "/community.GiftSrv/GetGifts", + "body": "test2" + } + ] +}' +``` + +```shell +[ + { + "status": 200, + "reason": "OK", + "body": "{\"ret\":500,\"msg\":\"error\",\"game_info\":null,\"gift\":[],\"to_gets\":0,\"get_all_msg\":\"\"}", + "headers": { + "Connection": "keep-alive", + "Date": "Sat, 11 Apr 2020 17:53:20 GMT", + "Content-Type": "application/json", + "Content-Length": "81", + "Server": "APISIX web server" + } + }, + { + "status": 200, + "reason": "OK", + "body": "{\"ret\":500,\"msg\":\"error\",\"game_info\":null,\"gift\":[],\"to_gets\":0,\"get_all_msg\":\"\"}", + "headers": { + "Connection": "keep-alive", + "Date": "Sat, 11 Apr 2020 17:53:20 GMT", + "Content-Type": "application/json", + "Content-Length": "81", + "Server": "APISIX web server" + } + } +] ``` ### Using custom URI @@ -79,10 +128,10 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ -H 'X-API-KEY: ' \ -H 'Content-Type: application/json' \ -d '{ - "uri": "/gen_token", - "plugins": { + "uri": "/batch-requests-gifs", + "plugins": { "public-api": { - "uri": "/apisix/plugin/jwt/sign" + "uri": "/apisix/batch-requests" } } }' @@ -91,7 +140,9 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ Now you can make requests to this new endpoint: ```shell -curl 'http://127.0.0.1:9080/gen_token?key=user-key' +curl --location --request POST 'http://127.0.0.1:9080/batch-requests-gifs' \ +--header 'Content-Type: application/json' \ +--data '{...}' ``` ### Securing the Route @@ -103,11 +154,9 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ -H 'X-API-KEY: ' \ -H 'Content-Type: application/json' \ -d '{ - "uri": "/gen_token", + "uri": "/batch-requests-gifs", "plugins": { - "public-api": { - "uri": "/apisix/plugin/jwt/sign" - }, + "public-api": {}, "key-auth": {} } }' @@ -116,8 +165,10 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ Now, only authenticated requests are allowed: ```shell -curl -i 'http://127.0.0.1:9080/gen_token?key=user-key' \ +curl --location --request POST 'http://127.0.0.1:9080/batch-requests-gifs' \ -H "apikey: test-apikey" + -H 'Content-Type: application/json' \ + --data '{...}' ``` ```shell @@ -127,7 +178,9 @@ HTTP/1.1 200 OK The below request will fail: ```shell -curl -i 'http://127.0.0.1:9080/gen_token?key=user-key' +curl --location --request POST 'http://127.0.0.1:9080/batch-requests-gifs' \ + -H 'Content-Type: application/json' \ + --data '{...}' ``` ```shell diff --git a/docs/zh/latest/plugin-develop.md b/docs/zh/latest/plugin-develop.md index c893088f454a..e1f64e16b53d 100644 --- a/docs/zh/latest/plugin-develop.md +++ b/docs/zh/latest/plugin-develop.md @@ -417,19 +417,20 @@ end ## 注册公共接口 -插件可以注册暴露给公网的接口。以 jwt-auth 插件为例,这个插件为了让客户端能够签名,注册了 `GET /apisix/plugin/jwt/sign` 这个接口: +插件可以注册暴露给公网的接口。以 batch-requests 插件为例,这个插件注册了 `POST /apisix/batch-requests` 接口,让客户端可以将多个 API 请求组合在一个请求/响应中: ```lua -local function gen_token() +function batch_requests() -- ... end function _M.api() + -- ... return { { - methods = {"GET"}, - uri = "/apisix/plugin/jwt/sign", - handler = gen_token, + methods = {"POST"}, + uri = "/apisix/batch-requests", + handler = batch_requests, } } end diff --git a/docs/zh/latest/plugins/jwt-auth.md b/docs/zh/latest/plugins/jwt-auth.md index eed13cf54df9..88065cb50cd9 100644 --- a/docs/zh/latest/plugins/jwt-auth.md +++ b/docs/zh/latest/plugins/jwt-auth.md @@ -43,13 +43,12 @@ Consumer 端: | key | string | 是 | | | Consumer 的 `access_key` 必须是唯一的。如果不同 Consumer 使用了相同的 `access_key` ,将会出现请求匹配异常。 | | secret | string | 否 | | | 加密秘钥。如果未指定,后台将会自动生成。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 | | public_key | string | 否 | | | RSA 或 ECDSA 公钥, `algorithm` 属性选择 `RS256` 或 `ES256` 算法时必选。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 | -| private_key | string | 否 | | | RSA 或 ECDSA 私钥, `algorithm` 属性选择 `RS256` 或 `ES256` 算法时必选。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 | | algorithm | string | 否 | "HS256" | ["HS256", "HS512", "RS256", "ES256"] | 加密算法。 | | exp | integer | 否 | 86400 | [1,...] | token 的超时时间。 | | base64_secret | boolean | 否 | false | | 当设置为 `true` 时,密钥为 base64 编码。 | | lifetime_grace_period | integer | 否 | 0 | [0,...] | 定义生成 JWT 的服务器和验证 JWT 的服务器之间的时钟偏移。该值应该是零(0)或一个正整数。 | -注意:schema 中还定义了 `encrypt_fields = {"secret", "private_key"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 +注意:schema 中还定义了 `encrypt_fields = {"secret"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 Route 端: @@ -62,16 +61,6 @@ Route 端: 您可以使用 [HashiCorp Vault](https://www.vaultproject.io/) 实施 `jwt-auth`,以从其[加密的 KV 引擎](https://developer.hashicorp.com/vault/docs/secrets/kv) 使用 [APISIX Secret](../terminology/secret.md) 资源。 -## 接口 - -该插件会增加 `/apisix/plugin/jwt/sign` 接口。 - -:::note - -你需要通过 [public-api](../../../en/latest/plugins/public-api.md) 插件来暴露它。 - -::: - ## 启用插件 如果想要启用插件,就必须使用 JWT token 创建一个 Consumer 对象,并将 Route 配置为使用 JWT 身份验证。 @@ -104,7 +93,7 @@ curl http://127.0.0.1:9180/apisix/admin/consumers \ :::note -`jwt-auth` 默认使用 `HS256` 算法,如果使用 `RS256` 算法,需要指定算法,并配置公钥与私钥,示例如下: +`jwt-auth` 默认使用 `HS256` 算法,如果使用 `RS256` 算法,需要指定算法,并配置公钥,示例如下: ```shell curl http://127.0.0.1:9180/apisix/admin/consumers \ @@ -115,7 +104,6 @@ curl http://127.0.0.1:9180/apisix/admin/consumers \ "jwt-auth": { "key": "user-key", "public_key": "-----BEGIN PUBLIC KEY-----\n……\n-----END PUBLIC KEY-----", - "private_key": "-----BEGIN RSA PRIVATE KEY-----\n……\n-----END RSA PRIVATE KEY-----", "algorithm": "RS256" } } @@ -146,54 +134,15 @@ curl http://127.0.0.1:9180/apisix/admin/routes/1 \ ## 测试插件 -首先,你需要为签发 token 的 API 配置一个 Route,该路由将使用 [public-api](../../../en/latest/plugins/public-api.md) 插件。 - -```shell -curl http://127.0.0.1:9180/apisix/admin/routes/jas \ --H "X-API-KEY: $admin_key" -X PUT -d ' -{ - "uri": "/apisix/plugin/jwt/sign", - "plugins": { - "public-api": {} - } -}' -``` - -之后就可以通过调用它来获取 token 了。 +首先你需要使用诸如 [JWT.io's debugger](https://jwt.io/#debugger-io) 等工具或编程语言来生成一个 JWT token。 -* 没有额外的 payload: - -```shell -curl http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i -``` - -``` -HTTP/1.1 200 OK -Date: Wed, 24 Jul 2019 10:33:31 GMT -Content-Type: text/plain -Transfer-Encoding: chunked -Connection: keep-alive -Server: APISIX web server - -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2NDA1MDgxMXx.Us8zh_4VjJXF-TmR5f8cif8mBU7SuefPlpxhH0jbPVI -``` - -* 有额外的 payload: +:::note -```shell -curl -G --data-urlencode 'payload={"uid":10000,"uname":"test"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i -``` +生成 JWT token 时,payload 中 `key` 字段是必要的,值为所要用到的凭证的 key; 且 `exp` 或 `nbf` 至少填写其中一个,值为 UNIX 时间戳。 -``` -HTTP/1.1 200 OK -Date: Wed, 21 Apr 2021 06:43:59 GMT -Content-Type: text/plain; charset=utf-8 -Transfer-Encoding: chunked -Connection: keep-alive -Server: APISIX/2.4 +示例:payload=`{"key": "user-key", "exp": 1727274983}` -eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmFtZSI6InRlc3QiLCJ1aWQiOjEwMDAwLCJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTYxOTA3MzgzOX0.jI9-Rpz1gc3u8Y6lZy8I43RXyCu0nSHANCvfn0YZUCY -``` +::: 现在你可以使用获取到的 token 进行请求尝试 diff --git a/docs/zh/latest/plugins/public-api.md b/docs/zh/latest/plugins/public-api.md index 0a50d0533c9d..56abc253237a 100644 --- a/docs/zh/latest/plugins/public-api.md +++ b/docs/zh/latest/plugins/public-api.md @@ -30,7 +30,7 @@ description: 本文介绍了 public-api 的相关操作,你可以使用 public `public-api` 插件可用于通过创建路由的方式暴露用户自定义的 API。 -你可以通过在路由中添加 `public-api` 插件,来保护**自定义插件为了实现特定功能**而暴露的 API。例如,你可以使用 [`jwt-auth`](./jwt-auth.md) 插件创建一个公共 API 端点 `/apisix/plugin/jwt/sign` 用于 JWT 认证。 +你可以通过在路由中添加 `public-api` 插件,来保护**自定义插件为了实现特定功能**而暴露的 API。例如,你可以使用 [batch-requests](./batch-requests.md) 插件创建一个公共 API 端点 `/apisix/batch-requests` 用于在一个请求中组合多个 API 请求。 :::note 注意 @@ -46,11 +46,11 @@ description: 本文介绍了 public-api 的相关操作,你可以使用 public ## 启用插件 -`public-api` 插件需要与授权插件一起配合使用,以下示例分别用到了 [`jwt-auth`](./jwt-auth.md) 插件和 [`key-auth`](./key-auth.md) 插件。 +`public-api` 插件需要与授权插件一起配合使用,以下示例分别用到了 [batch-requests](./batch-requests.md) 插件和 [`key-auth`](./key-auth.md) ### 基本用法 -首先,你需要启用并配置 `jwt-auth` 插件,详细使用方法请参考 [`jwt-auth`](./jwt-auth.md) 插件文档。 +首先,你需要启用并配置 `batch-requests` 插件,详细使用方法请参考 [batch-requests](./batch-requests.md) 插件文档。 然后,使用以下命令在指定路由上启用并配置 `public-api` 插件: @@ -66,11 +66,11 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ```shell curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r1' \ - -H "X-API-KEY: $admin_key" \ + -H 'X-API-KEY: ' \ -H 'Content-Type: application/json' \ -d '{ - "uri": "/apisix/plugin/jwt/sign", - "plugins": { + "uri": "/apisix/batch-requests", + "plugins": { "public-api": {} } }' @@ -78,31 +78,76 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r1' \ **测试插件** -向配置的 URI 发出访问请求,如果返回一个包含 JWT Token 的响应,则代表插件生效: +向配置的 URI 发出访问请求,会返回一个包含多个 API 请求结果的的响应: ```shell -curl 'http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key' +curl --location --request POST 'http://127.0.0.1:9080/apisix/batch-requests' \ +--header 'Content-Type: application/json' \ +--data '{ + "headers": { + "Content-Type": "application/json", + "admin-jwt":"xxxx" + }, + "timeout": 500, + "pipeline": [ + { + "method": "POST", + "path": "/community.GiftSrv/GetGifts", + "body": "test" + }, + { + "method": "POST", + "path": "/community.GiftSrv/GetGifts", + "body": "test2" + } + ] +}' ``` ```shell -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk0Mjg1MzIsImtleSI6InVzZXIta2V5In0.NhrWrO-da4kXezxTLdgFBX2rJA2dF1qESs8IgmwhNd0 +[ + { + "status": 200, + "reason": "OK", + "body": "{\"ret\":500,\"msg\":\"error\",\"game_info\":null,\"gift\":[],\"to_gets\":0,\"get_all_msg\":\"\"}", + "headers": { + "Connection": "keep-alive", + "Date": "Sat, 11 Apr 2020 17:53:20 GMT", + "Content-Type": "application/json", + "Content-Length": "81", + "Server": "APISIX web server" + } + }, + { + "status": 200, + "reason": "OK", + "body": "{\"ret\":500,\"msg\":\"error\",\"game_info\":null,\"gift\":[],\"to_gets\":0,\"get_all_msg\":\"\"}", + "headers": { + "Connection": "keep-alive", + "Date": "Sat, 11 Apr 2020 17:53:20 GMT", + "Content-Type": "application/json", + "Content-Length": "81", + "Server": "APISIX web server" + } + } +] ``` ### 使用自定义 URI -首先,你需要启用并配置 `jwt-auth` 插件,详细使用方法请参考 [`jwt-auth`](./jwt-auth.md) 插件文档。 +首先,你需要启用并配置 `batch-requests` 插件,详细使用方法请参考 [batch-requests](./batch-requests.md) 插件文档。 然后,你可以使用一个自定义的 URI 来暴露 API: ```shell curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ - -H "X-API-KEY: $admin_key" \ + -H 'X-API-KEY: ' \ -H 'Content-Type: application/json' \ -d '{ - "uri": "/gen_token", - "plugins": { + "uri": "/batch-requests-gifs", + "plugins": { "public-api": { - "uri": "/apisix/plugin/jwt/sign" + "uri": "/apisix/batch-requests" } } }' @@ -110,14 +155,12 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ **测试插件** -向自定义的 URI 发出访问请求,如果返回一个包含 JWT Token 的响应,则代表插件生效: +向自定义的 URI 发出访问请求,如果返回一个包含多个 API 请求结果的响应,则代表插件生效: ```shell -curl 'http://127.0.0.1:9080/gen_token?key=user-key' -``` - -```shell -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk0Mjg1NjIsImtleSI6InVzZXIta2V5In0.UVkXWbyGb8ajBNtxs0iAaFb2jTEWIlqTR125xr1ZMLc +curl --location --request POST 'http://127.0.0.1:9080/batch-requests-gifs' \ +--header 'Content-Type: application/json' \ +--data '{...}' ``` ### 确保 Route 安全 @@ -126,17 +169,13 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk0Mjg1NjIsImtleSI6InVzZXIta2V ```shell curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ - -H "X-API-KEY: $admin_key" \ + -H 'X-API-KEY: ' \ -H 'Content-Type: application/json' \ -d '{ - "uri": "/gen_token", + "uri": "/batch-requests-gifs", "plugins": { - "public-api": { - "uri": "/apisix/plugin/jwt/sign" - }, - "key-auth": { - "key": "test-apikey" - } + "public-api": {}, + "key-auth": {} } }' ``` @@ -148,8 +187,10 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \ 发出访问请求并指定 `apikey`,如果返回 `200` HTTP 状态码,则说明请求被允许: ```shell -curl -i 'http://127.0.0.1:9080/gen_token?key=user-key' \ +curl --location --request POST 'http://127.0.0.1:9080/batch-requests-gifs' \ -H "apikey: test-apikey" + -H 'Content-Type: application/json' \ + --data '{...}' ``` ```shell @@ -159,7 +200,9 @@ HTTP/1.1 200 OK 发出访问请求,如果返回 `401` HTTP 状态码,则说明请求被阻止,插件生效: ```shell -curl -i 'http://127.0.0.1:9080/gen_token?key=user-key' +curl --location --request POST 'http://127.0.0.1:9080/batch-requests-gifs' \ + -H 'Content-Type: application/json' \ + --data '{...}' ``` ```shell diff --git a/t/config-center-yaml/consumer.t b/t/config-center-yaml/consumer.t index 4fb356185933..7a3709203711 100644 --- a/t/config-center-yaml/consumer.t +++ b/t/config-center-yaml/consumer.t @@ -60,46 +60,7 @@ property "username" validation failed -=== TEST 2: validate the plugin under consumer ---- apisix_yaml -routes: - - uri: /apisix/plugin/jwt/sign - plugins: - public-api: {} -consumers: - - username: jwt - plugins: - jwt-auth: - secret: my-secret-key -#END ---- request -GET /apisix/plugin/jwt/sign?key=user-key ---- error_log -plugin jwt-auth err: property "key" is required ---- error_code: 404 - - - -=== TEST 3: provide default value for the plugin ---- apisix_yaml -routes: - - uri: /apisix/plugin/jwt/sign - plugins: - public-api: {} -consumers: - - username: jwt - plugins: - jwt-auth: - key: user-key - secret: my-secret-key -#END ---- request -GET /apisix/plugin/jwt/sign?key=user-key ---- error_code: 200 - - - -=== TEST 4: consumer restriction +=== TEST 2: consumer restriction --- apisix_yaml consumers: - username: jack diff --git a/t/lib/apisix/plugins/jwt-auth.lua b/t/lib/apisix/plugins/jwt-auth.lua new file mode 100644 index 000000000000..56b5b1f3326d --- /dev/null +++ b/t/lib/apisix/plugins/jwt-auth.lua @@ -0,0 +1,122 @@ +-- +-- 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. +-- + +local core = require("apisix.core") +local jwt = require("resty.jwt") + +local ngx_time = ngx.time +local ngx_decode_base64 = ngx.decode_base64 +local pcall = pcall + + +local _M = {} + + +local function get_secret(conf) + local secret = conf.secret + + if conf.base64_secret then + return ngx_decode_base64(secret) + end + + return secret +end + +local function get_real_payload(key, exp, payload) + local real_payload = { + key = key, + exp = ngx_time() + exp + } + if payload then + local extra_payload = core.json.decode(payload) + core.table.merge(extra_payload, real_payload) + return extra_payload + end + return real_payload +end + +local function sign_jwt_with_HS(key, auth_conf, payload) + local auth_secret, err = get_secret(auth_conf) + if not auth_secret then + core.log.error("failed to sign jwt, err: ", err) + return nil, "failed to sign jwt: failed to get auth_secret" + end + local ok, jwt_token = pcall(jwt.sign, _M, + auth_secret, + { + header = { + typ = "JWT", + alg = auth_conf.algorithm + }, + payload = get_real_payload(key, auth_conf.exp, payload) + } + ) + if not ok then + core.log.error("failed to sign jwt, err: ", jwt_token.reason) + return nil, "failed to sign jwt" + end + return jwt_token +end + +local function sign_jwt_with_RS256_ES256(key, auth_conf, payload) + local ok, jwt_token = pcall(jwt.sign, _M, + auth_conf.private_key, + { + header = { + typ = "JWT", + alg = auth_conf.algorithm, + x5c = { + auth_conf.public_key, + } + }, + payload = get_real_payload(key, auth_conf.exp, payload) + } + ) + if not ok then + core.log.error("failed to sign jwt, err: ", jwt_token.reason) + return nil, "failed to sign jwt" + end + return jwt_token +end + +local function get_sign_handler(algorithm) + if not algorithm or algorithm == "HS256" or algorithm == "HS512" then + return sign_jwt_with_HS + elseif algorithm == "RS256" or algorithm == "ES256" then + return sign_jwt_with_RS256_ES256 + end +end + +local function gen_token(auth_conf, payload) + if not auth_conf.exp then + auth_conf.exp = 86400 + end + if not auth_conf.lifetime_grace_period then + auth_conf.lifetime_grace_period = 0 + end + if not auth_conf.algorithm then + auth_conf.algorithm = "HS256" + end + local sign_handler = get_sign_handler(auth_conf.algorithm) + local jwt_token, err = sign_handler(auth_conf.key, auth_conf, payload) + return jwt_token, err +end + + +_M.gen_token = gen_token + +return _M diff --git a/t/plugin/jwt-auth.t b/t/plugin/jwt-auth.t index f47b37c96457..1c28123e3b7b 100644 --- a/t/plugin/jwt-auth.t +++ b/t/plugin/jwt-auth.t @@ -135,68 +135,7 @@ passed -=== TEST 5: create public API route (jwt-auth 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/jwt/sign" - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- response_body -passed - - - -=== TEST 6: sign / verify in argument ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/hello?jwt=' .. sign, - ngx.HTTP_GET - ) - - ngx.status = code - ngx.print(res) - } - } ---- response_body -hello world - - - -=== TEST 7: test for unsupported method ---- request -PATCH /apisix/plugin/jwt/sign?key=user-key ---- error_code: 404 - - - -=== TEST 8: verify, missing token +=== TEST 5: verify, missing token --- request GET /hello --- error_code: 401 @@ -205,7 +144,7 @@ GET /hello -=== TEST 9: verify: invalid JWT token +=== TEST 6: verify: invalid JWT token --- request GET /hello?jwt=invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.pPNVvh-TQsdDzorRwa-uuiLYiEBODscp9wv0cwD6c68 --- error_code: 401 @@ -216,7 +155,7 @@ JWT token invalid: invalid header: invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 -=== TEST 10: verify: expired JWT token +=== TEST 7: verify: expired JWT token --- request GET /hello?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.pPNVvh-TQsdDzorRwa-uuiLYiEBODscp9wv0cwD6c68 --- error_code: 401 @@ -227,7 +166,7 @@ failed to verify jwt: 'exp' claim expired at Tue, 23 Jul 2019 08:28:21 GMT -=== TEST 11: verify (in header) +=== TEST 8: verify (in header) --- request GET /hello --- more_headers @@ -237,7 +176,7 @@ hello world -=== TEST 12: verify (in cookie) +=== TEST 9: verify (in cookie) --- request GET /hello --- more_headers @@ -247,7 +186,7 @@ hello world -=== TEST 13: verify (in header without Bearer) +=== TEST 10: verify (in header without Bearer) --- request GET /hello --- more_headers @@ -257,7 +196,7 @@ hello world -=== TEST 14: verify (header with bearer) +=== TEST 11: verify (header with bearer) --- request GET /hello --- more_headers @@ -267,7 +206,7 @@ hello world -=== TEST 15: verify (invalid bearer token) +=== TEST 12: verify (invalid bearer token) --- request GET /hello --- more_headers @@ -280,7 +219,7 @@ JWT token invalid: invalid header: invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 -=== TEST 16: delete a exist consumer +=== TEST 13: delete a exist consumer --- config location /t { content_by_lua_block { @@ -318,22 +257,16 @@ JWT token invalid: invalid header: invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 code, body = t('/apisix/admin/consumers/jack', ngx.HTTP_DELETE) ngx.say("code: ", code < 300, " body: ", body) - - ngx.sleep(1) - code, body = t('/apisix/plugin/jwt/sign?key=chen-key', - ngx.HTTP_GET) - ngx.say("code: ", code < 300, " body: ", body) } } --- response_body code: true body: passed code: true body: passed code: true body: passed -code: true body: passed -=== TEST 17: add consumer with username and plugins with base64 secret +=== TEST 14: add consumer with username and plugins with base64 secret --- config location /t { content_by_lua_block { @@ -363,7 +296,7 @@ passed -=== TEST 18: enable jwt auth plugin with base64 secret +=== TEST 15: enable jwt auth plugin with base64 secret --- config location /t { content_by_lua_block { @@ -394,21 +327,14 @@ passed -=== TEST 19: sign / verify +=== TEST 16: sign / verify --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- sign is generated via https://jwt.io/#debugger-io. This is the case for all other test cases and is not specified further + local sign = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30._Z8b_Asb2ROvGX4R5sNMbgJNQXB6x7aQeuVjmjY21Nw" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -422,7 +348,7 @@ hello world -=== TEST 20: verify: invalid JWT token +=== TEST 17: verify: invalid JWT token --- request GET /hello?jwt=invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTU2Mzg3MDUwMX0.pPNVvh-TQsdDzorRwa-uuiLYiEBODscp9wv0cwD6c68 --- error_code: 401 @@ -433,7 +359,7 @@ JWT token invalid: invalid header: invalid-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 -=== TEST 21: verify: invalid signature +=== TEST 18: verify: invalid signature --- request GET /hello --- more_headers @@ -446,7 +372,7 @@ failed to verify jwt: signature mismatch: fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnV -=== TEST 22: verify: happy path +=== TEST 19: verify: happy path --- request GET /hello --- more_headers @@ -456,7 +382,7 @@ hello world -=== TEST 23: without key +=== TEST 20: without key --- config location /t { content_by_lua_block { @@ -476,7 +402,7 @@ property "key" is required -=== TEST 24: get the schema by schema_type +=== TEST 21: get the schema by schema_type --- config location /t { content_by_lua_block { @@ -484,7 +410,7 @@ property "key" is required local code, body, raw = t('/apisix/admin/schema/plugins/jwt-auth?schema_type=consumer', ngx.HTTP_GET, [[ -{"dependencies":{"algorithm":{"oneOf":[{"properties":{"algorithm":{"default":"HS256","enum":["HS256","HS512"]}}},{"required":["public_key","private_key"],"properties":{"algorithm":{"enum":["RS256","ES256"]},"public_key":{"type":"string"},"private_key":{"type":"string"}}}]}},"required":["key"],"type":"object","properties":{"base64_secret":{"default":false,"type":"boolean"},"secret":{"type":"string"},"algorithm":{"enum":["HS256","HS512","RS256","ES256"],"default":"HS256","type":"string"},"exp":{"minimum":1,"default":86400,"type":"integer"},"key":{"type":"string"}}} +{"dependencies":{"algorithm":{"oneOf":[{"properties":{"algorithm":{"default":"HS256","enum":["HS256","HS512"]}}},{"required":["public_key"],"properties":{"algorithm":{"enum":["RS256","ES256"]},"public_key":{"type":"string"}}}]}},"required":["key"],"type":"object","properties":{"base64_secret":{"default":false,"type":"boolean"},"secret":{"type":"string"},"algorithm":{"enum":["HS256","HS512","RS256","ES256"],"default":"HS256","type":"string"},"exp":{"minimum":1,"default":86400,"type":"integer"},"key":{"type":"string"}}} ]] ) @@ -494,7 +420,7 @@ property "key" is required -=== TEST 25: get the schema by error schema_type +=== TEST 22: get the schema by error schema_type --- config location /t { content_by_lua_block { @@ -512,7 +438,7 @@ property "key" is required -=== TEST 26: get the schema by default schema_type +=== TEST 23: get the schema by default schema_type --- config location /t { content_by_lua_block { @@ -530,7 +456,7 @@ property "key" is required -=== TEST 27: add consumer with username and plugins with public_key, private_key(private_key numbits = 512) +=== TEST 24: add consumer with username and plugins with public_key --- config location /t { content_by_lua_block { @@ -543,8 +469,7 @@ property "key" is required "jwt-auth": { "key": "user-key-rs256", "algorithm": "RS256", - "public_key": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr\n7noq/0ukiZqVQLSJPMOv0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQ==\n-----END PUBLIC KEY-----", - "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv\n0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7\n+pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL\nwQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF\nIeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb\n2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs\nYvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG\n-----END RSA PRIVATE KEY-----" + "public_key": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr\n7noq/0ukiZqVQLSJPMOv0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQ==\n-----END PUBLIC KEY-----" } } }]] @@ -563,7 +488,7 @@ passed -=== TEST 28: JWT sign and verify use RS256 algorithm(private_key numbits = 512) +=== TEST 25: JWT sign and verify use RS256 algorithm --- config location /t { content_by_lua_block { @@ -597,21 +522,16 @@ passed -=== TEST 29: sign/verify use RS256 algorithm(private_key numbits = 512) +=== TEST 26: sign/verify use RS256 algorithm(private_key numbits = 512) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this private_key + -- private_key = "-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv\n0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7\n+pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL\nwQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF\nIeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb\n2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs\nYvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG\n-----END RSA PRIVATE KEY-----" + local sign = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsIm5iZiI6MTcyNzI3NDk4M30.FaV6N-bWaSXkRrF2ec28hH5QENl-8I0LCONdNnQpB1YOb4akP-lKnwtABgfsQ_eKaEIf1PWNoghyByLejXaPbQ" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -627,7 +547,7 @@ hello world -=== TEST 30: add consumer with username and plugins with public_key, private_key(private_key numbits = 1024) +=== TEST 27: add consumer with username and plugins with public_key --- config location /t { content_by_lua_block { @@ -640,9 +560,7 @@ hello world "jwt-auth": { "key": "user-key-rs256", "algorithm": "RS256", - "public_key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGxOfVe/seP5T/V8pkS5YNAPRC\n3Ffxxedi7v0pyZh/4d4p9Qx0P9wOmALwlOq4Ftgks311pxG0zL0LcTJY4ikbc3r0\nh8SM0yhj9UV1VGtuia4YakobvpM9U+kq3lyIMO9ZPRez0cP3AJIYCt5yf8E7bNYJ\njbJNjl8WxvM1tDHqVQIDAQAB\n-----END PUBLIC KEY-----", - ]] .. [[ - "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDGxOfVe/seP5T/V8pkS5YNAPRC3Ffxxedi7v0pyZh/4d4p9Qx0\nP9wOmALwlOq4Ftgks311pxG0zL0LcTJY4ikbc3r0h8SM0yhj9UV1VGtuia4Yakob\nvpM9U+kq3lyIMO9ZPRez0cP3AJIYCt5yf8E7bNYJjbJNjl8WxvM1tDHqVQIDAQAB\nAoGAYFy9eAXvLC7u8QuClzT9vbgksvVXvWKQVqo+GbAeOoEpz3V5YDJFYN3ZLwFC\n+ZQ5nTFXNV6Veu13CMEMA4NBIa8I4r3aYzSjq7X7UEBkLDBtEUge52mYakNfXD8D\nqViHkyJqvtVnBl7jNZVqbBderQnXA0kigaeZPL3+hkYKBgECQQDmiDbUL3FBynLy\nNX6/JdAbO4g1Nl/1RsGg8svhb6vRM8WQyIQWt5EKi7yoP/9nIRXcIgdwpVO6wZRU\nDojL0oy1AkEA3LpjqXxIRzcy2ALsqKN3hoNPGAlkPyG3Mlph91mqSZ2jYpXCX9LW\nhhQdf9GmfO8jZtYhYAJqEMOJrKeZHToLIQJBAJbrJbnTNTn05ztZehh5ELxDRPBR\nIJDaOXi8emyjRsA2PGiEXLTih7l3sZIUE4fYSQ9L18MO+LmScSB2Q2fr9uECQFc7\nIh/dCgN7ARD1Nun+kEIMqrlpHMEGZgv0RDsoqG+naOaRINwVysn6MR5OkGlXaLo/\nbbkvuxMc88/T/GLciYECQQC4oUveCOic4Qs6TQfMUKKv/kJ09slbD70HkcBzA5nY\nyro4RT4z/SN6T3SD+TuWn2//I5QxiQEIbOCTySci7yuh\n-----END RSA PRIVATE KEY-----" + "public_key": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGxOfVe/seP5T/V8pkS5YNAPRC\n3Ffxxedi7v0pyZh/4d4p9Qx0P9wOmALwlOq4Ftgks311pxG0zL0LcTJY4ikbc3r0\nh8SM0yhj9UV1VGtuia4YakobvpM9U+kq3lyIMO9ZPRez0cP3AJIYCt5yf8E7bNYJ\njbJNjl8WxvM1tDHqVQIDAQAB\n-----END PUBLIC KEY-----" } } } @@ -659,7 +577,7 @@ passed -=== TEST 31: JWT sign and verify use RS256 algorithm(private_key numbits = 1024) +=== TEST 28: JWT sign and verify use RS256 algorithm --- config location /t { content_by_lua_block { @@ -693,21 +611,16 @@ passed -=== TEST 32: sign/verify use RS256 algorithm(private_key numbits = 1024) +=== TEST 29: sign/verify use RS256 algorithm(private_key numbits = 1024) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this private_key + -- private_key = "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDGxOfVe/seP5T/V8pkS5YNAPRC3Ffxxedi7v0pyZh/4d4p9Qx0\nP9wOmALwlOq4Ftgks311pxG0zL0LcTJY4ikbc3r0h8SM0yhj9UV1VGtuia4Yakob\nvpM9U+kq3lyIMO9ZPRez0cP3AJIYCt5yf8E7bNYJjbJNjl8WxvM1tDHqVQIDAQAB\nAoGAYFy9eAXvLC7u8QuClzT9vbgksvVXvWKQVqo+GbAeOoEpz3V5YDJFYN3ZLwFC\n+ZQ5nTFXNV6Veu13CMEMA4NBIa8I4r3aYzSjq7X7UEBkLDBtEUge52mYakNfXD8D\nqViHkyJqvtVnBl7jNZVqbBderQnXA0kigaeZPL3+hkYKBgECQQDmiDbUL3FBynLy\nNX6/JdAbO4g1Nl/1RsGg8svhb6vRM8WQyIQWt5EKi7yoP/9nIRXcIgdwpVO6wZRU\nDojL0oy1AkEA3LpjqXxIRzcy2ALsqKN3hoNPGAlkPyG3Mlph91mqSZ2jYpXCX9LW\nhhQdf9GmfO8jZtYhYAJqEMOJrKeZHToLIQJBAJbrJbnTNTn05ztZehh5ELxDRPBR\nIJDaOXi8emyjRsA2PGiEXLTih7l3sZIUE4fYSQ9L18MO+LmScSB2Q2fr9uECQFc7\nIh/dCgN7ARD1Nun+kEIMqrlpHMEGZgv0RDsoqG+naOaRINwVysn6MR5OkGlXaLo/\nbbkvuxMc88/T/GLciYECQQC4oUveCOic4Qs6TQfMUKKv/kJ09slbD70HkcBzA5nY\nyro4RT4z/SN6T3SD+TuWn2//I5QxiQEIbOCTySci7yuh\n-----END RSA PRIVATE KEY-----" + local sign = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsIm5iZiI6MTcyNzI3NDk4M30.FG-PAyscR-pFyw1a5ZiRxHLxzSI1jyVyZxm-fj3-u5igjacJY7UByCUKDnieV9-Ft81X15gdHAcrumUsTbu-77F50Bp5A1sxzdL_PXVLJ1cc8UP2ltvQwf1YWdutK7CI_uNLaeCYPZd9tWPhnfpsv4AdTdaCWeFyoaZSNOdw4oA" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -723,21 +636,17 @@ hello world -=== TEST 33: sign/verify use RS256 algorithm(private_key numbits = 1024,with extra payload) +=== TEST 30: sign/verify use RS256 algorithm(private_key numbits = 1024,with extra payload) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256&payload=%7B%22aaa%22%3A%2211%22%2C%22bb%22%3A%22222%22%7D', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this private_key and payload + -- private_key = "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQDGxOfVe/seP5T/V8pkS5YNAPRC3Ffxxedi7v0pyZh/4d4p9Qx0\nP9wOmALwlOq4Ftgks311pxG0zL0LcTJY4ikbc3r0h8SM0yhj9UV1VGtuia4Yakob\nvpM9U+kq3lyIMO9ZPRez0cP3AJIYCt5yf8E7bNYJjbJNjl8WxvM1tDHqVQIDAQAB\nAoGAYFy9eAXvLC7u8QuClzT9vbgksvVXvWKQVqo+GbAeOoEpz3V5YDJFYN3ZLwFC\n+ZQ5nTFXNV6Veu13CMEMA4NBIa8I4r3aYzSjq7X7UEBkLDBtEUge52mYakNfXD8D\nqViHkyJqvtVnBl7jNZVqbBderQnXA0kigaeZPL3+hkYKBgECQQDmiDbUL3FBynLy\nNX6/JdAbO4g1Nl/1RsGg8svhb6vRM8WQyIQWt5EKi7yoP/9nIRXcIgdwpVO6wZRU\nDojL0oy1AkEA3LpjqXxIRzcy2ALsqKN3hoNPGAlkPyG3Mlph91mqSZ2jYpXCX9LW\nhhQdf9GmfO8jZtYhYAJqEMOJrKeZHToLIQJBAJbrJbnTNTn05ztZehh5ELxDRPBR\nIJDaOXi8emyjRsA2PGiEXLTih7l3sZIUE4fYSQ9L18MO+LmScSB2Q2fr9uECQFc7\nIh/dCgN7ARD1Nun+kEIMqrlpHMEGZgv0RDsoqG+naOaRINwVysn6MR5OkGlXaLo/\nbbkvuxMc88/T/GLciYECQQC4oUveCOic4Qs6TQfMUKKv/kJ09slbD70HkcBzA5nY\nyro4RT4z/SN6T3SD+TuWn2//I5QxiQEIbOCTySci7yuh\n-----END RSA PRIVATE KEY-----" + -- payload = {"aaa":"11","bb":"222"} + local sign = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsIm5iZiI6MTcyNzI3NDk4M30.FG-PAyscR-pFyw1a5ZiRxHLxzSI1jyVyZxm-fj3-u5igjacJY7UByCUKDnieV9-Ft81X15gdHAcrumUsTbu-77F50Bp5A1sxzdL_PXVLJ1cc8UP2ltvQwf1YWdutK7CI_uNLaeCYPZd9tWPhnfpsv4AdTdaCWeFyoaZSNOdw4oA" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -753,7 +662,7 @@ hello world -=== TEST 34: add consumer with username and plugins with public_key, private_key(private_key numbits = 2048) +=== TEST 31: add consumer with username and plugins with public_key --- config location /t { content_by_lua_block { @@ -766,9 +675,7 @@ hello world "jwt-auth": { "key": "user-key-rs256", "algorithm": "RS256", - "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5LHjZ4FxQ9jk6eQGDRt\noRwFVkLq+dUBebs97hrzirokVr2B+RoxqdLfKAM+AsN2DadawZ2GqlCV9DL0/gz6\nnWSqTQpWbQ8c7CrF31EkIHUYRzZvWy17K3WC9Odk/gM1FVd0HbZ2Rjuqj9ADeeqx\nnj9npDqKrMODOENy31SqZNerWZsdgGkML5JYbX5hbI2L9LREvRU21fDgSfGL6Mw4\nNaxnnzcvll4yqwrBELSeDZEAt0+e/p1dO7moxF+b1pFkh9vQl6zGvnvf8fOqn5Ex\ntLHXVzgx752PHMwmuj9mO1ko6p8FOM0JHDnooI+5rwK4j3I27Ho5nnatVWUaxK4U\n8wIDAQAB\n-----END PUBLIC KEY-----", - ]] .. [[ - "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAv5LHjZ4FxQ9jk6eQGDRtoRwFVkLq+dUBebs97hrzirokVr2B\n+RoxqdLfKAM+AsN2DadawZ2GqlCV9DL0/gz6nWSqTQpWbQ8c7CrF31EkIHUYRzZv\nWy17K3WC9Odk/gM1FVd0HbZ2Rjuqj9ADeeqxnj9npDqKrMODOENy31SqZNerWZsd\ngGkML5JYbX5hbI2L9LREvRU21fDgSfGL6Mw4Naxnnzcvll4yqwrBELSeDZEAt0+e\n/p1dO7moxF+b1pFkh9vQl6zGvnvf8fOqn5ExtLHXVzgx752PHMwmuj9mO1ko6p8F\nOM0JHDnooI+5rwK4j3I27Ho5nnatVWUaxK4U8wIDAQABAoIBAFsFQC73H8KrNyKW\ngI4fit77U0XS8ZXWMKdH4XrZ71DAdDeKPtC+M05+1GxMbhAeEl8WXraTQ8J0G2s1\nMtXqEMDrbUbBXKLghVtoTy91e/a369sZ7/qgN19Eq/30WzWdDIGhVZgwcy2Xd8hw\nitZIPi/z7ChJcE35bsUytseJkJPsWeMJNq4mLbHqMSBQWze/vNvIeGYr2xfqXc6H\nywGWGlk46RI28mOf7PecU0DxFoTBNcntZrpOwaIrTDsC7E6uNvhVbtsneseTlQuj\nihS7DAH72Zx3CXc9+SL3b5QNRD1Rnp+gKM6itjW1yduOj2dS0p8YzcUYNtxnw5Gv\nuLoHwuECgYEA58NhvnHn10YLBEMYxb30tDobdGfOjBSfih8K53+/SJhqF5mv4qZX\nUfw3o5R+CkkrhbZ24yst7wqKFYZ+LfazOqljOPOrBsgIIry/sXBlcbGLCw9MYFfB\nejKTt/xZjqLdDCcEbiSB0L2xNuyF/TZOu8V5Nu55LXKBqeW4yISQ5FkCgYEA05t1\n2cq8gE1jMfGXQNFIpUDG2j4wJXAPqnJZSUF/BICa55mH/HYRKoP2uTSvAnqNrdGt\nsnjnnMA7T+fGogB4STif1POWfj+BTKVa/qhUX9ytH6TeI4aqPXSZdTVEPRfR7bG1\nIB/j2lyPkiNi2VijMx33xqxIaQUUsvxIT95GSisCgYAdaJFylQmSK3UiaVEvZlcy\nt1zcfH+dDtDfueisT216TLzJmdrTq7/Qy2xT+Xe03mwDX4/ea5A8kN3MtXA1bOR5\nQR0yENlW1vMRVVoNrfFxZ9H46UwLvZbzZo+P/RlwHAJolFrfjwpZ7ngaPBEUfFup\nP/mNmt0Ng0YoxNmZuBiaoQKBgQCa2d4RRgpRvdAEYW41UbHetJuQZAfprarZKZrr\nP9HKoq45I6Je/qurOCzZ9ZLItpRtic6Zl16u2AHPhKZYMQ3VT2mvdZ5AvwpI44zG\nZLpx+FR8nrKsvsRf+q6+Ff/c0Uyfq/cHDi84wZmS8PBKa1Hqe1ix+6t1pvEx1eq4\n/8jiRwKBgGOZzt5H5P0v3cFG9EUPXtvf2k81GmZjlDWu1gu5yWSYpqCfYr/K/1Md\ndaQ/YCKTc12SYL7hZ2j+2/dGFXNXwknIyKNj76UxjUpJywWI5mUaXJZJDkLCRvxF\nkk9nWvPorpjjjxaIVN+TkGgDd/60at/tI6HxzZitVyla5rB8hoPm\n-----END RSA PRIVATE KEY-----" + "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5LHjZ4FxQ9jk6eQGDRt\noRwFVkLq+dUBebs97hrzirokVr2B+RoxqdLfKAM+AsN2DadawZ2GqlCV9DL0/gz6\nnWSqTQpWbQ8c7CrF31EkIHUYRzZvWy17K3WC9Odk/gM1FVd0HbZ2Rjuqj9ADeeqx\nnj9npDqKrMODOENy31SqZNerWZsdgGkML5JYbX5hbI2L9LREvRU21fDgSfGL6Mw4\nNaxnnzcvll4yqwrBELSeDZEAt0+e/p1dO7moxF+b1pFkh9vQl6zGvnvf8fOqn5Ex\ntLHXVzgx752PHMwmuj9mO1ko6p8FOM0JHDnooI+5rwK4j3I27Ho5nnatVWUaxK4U\n8wIDAQAB\n-----END PUBLIC KEY-----" } } } @@ -784,7 +691,7 @@ passed -=== TEST 35: JWT sign and verify use RS256 algorithm(private_key numbits = 2048) +=== TEST 32: JWT sign and verify use RS256 algorithm(private_key numbits = 2048) --- config location /t { content_by_lua_block { @@ -816,21 +723,16 @@ passed -=== TEST 36: sign/verify use RS256 algorithm(private_key numbits = 2048) +=== TEST 33: sign/verify use RS256 algorithm(private_key numbits = 2048) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this private_key + -- private_key = "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAv5LHjZ4FxQ9jk6eQGDRtoRwFVkLq+dUBebs97hrzirokVr2B\n+RoxqdLfKAM+AsN2DadawZ2GqlCV9DL0/gz6nWSqTQpWbQ8c7CrF31EkIHUYRzZv\nWy17K3WC9Odk/gM1FVd0HbZ2Rjuqj9ADeeqxnj9npDqKrMODOENy31SqZNerWZsd\ngGkML5JYbX5hbI2L9LREvRU21fDgSfGL6Mw4Naxnnzcvll4yqwrBELSeDZEAt0+e\n/p1dO7moxF+b1pFkh9vQl6zGvnvf8fOqn5ExtLHXVzgx752PHMwmuj9mO1ko6p8F\nOM0JHDnooI+5rwK4j3I27Ho5nnatVWUaxK4U8wIDAQABAoIBAFsFQC73H8KrNyKW\ngI4fit77U0XS8ZXWMKdH4XrZ71DAdDeKPtC+M05+1GxMbhAeEl8WXraTQ8J0G2s1\nMtXqEMDrbUbBXKLghVtoTy91e/a369sZ7/qgN19Eq/30WzWdDIGhVZgwcy2Xd8hw\nitZIPi/z7ChJcE35bsUytseJkJPsWeMJNq4mLbHqMSBQWze/vNvIeGYr2xfqXc6H\nywGWGlk46RI28mOf7PecU0DxFoTBNcntZrpOwaIrTDsC7E6uNvhVbtsneseTlQuj\nihS7DAH72Zx3CXc9+SL3b5QNRD1Rnp+gKM6itjW1yduOj2dS0p8YzcUYNtxnw5Gv\nuLoHwuECgYEA58NhvnHn10YLBEMYxb30tDobdGfOjBSfih8K53+/SJhqF5mv4qZX\nUfw3o5R+CkkrhbZ24yst7wqKFYZ+LfazOqljOPOrBsgIIry/sXBlcbGLCw9MYFfB\nejKTt/xZjqLdDCcEbiSB0L2xNuyF/TZOu8V5Nu55LXKBqeW4yISQ5FkCgYEA05t1\n2cq8gE1jMfGXQNFIpUDG2j4wJXAPqnJZSUF/BICa55mH/HYRKoP2uTSvAnqNrdGt\nsnjnnMA7T+fGogB4STif1POWfj+BTKVa/qhUX9ytH6TeI4aqPXSZdTVEPRfR7bG1\nIB/j2lyPkiNi2VijMx33xqxIaQUUsvxIT95GSisCgYAdaJFylQmSK3UiaVEvZlcy\nt1zcfH+dDtDfueisT216TLzJmdrTq7/Qy2xT+Xe03mwDX4/ea5A8kN3MtXA1bOR5\nQR0yENlW1vMRVVoNrfFxZ9H46UwLvZbzZo+P/RlwHAJolFrfjwpZ7ngaPBEUfFup\nP/mNmt0Ng0YoxNmZuBiaoQKBgQCa2d4RRgpRvdAEYW41UbHetJuQZAfprarZKZrr\nP9HKoq45I6Je/qurOCzZ9ZLItpRtic6Zl16u2AHPhKZYMQ3VT2mvdZ5AvwpI44zG\nZLpx+FR8nrKsvsRf+q6+Ff/c0Uyfq/cHDi84wZmS8PBKa1Hqe1ix+6t1pvEx1eq4\n/8jiRwKBgGOZzt5H5P0v3cFG9EUPXtvf2k81GmZjlDWu1gu5yWSYpqCfYr/K/1Md\ndaQ/YCKTc12SYL7hZ2j+2/dGFXNXwknIyKNj76UxjUpJywWI5mUaXJZJDkLCRvxF\nkk9nWvPorpjjjxaIVN+TkGgDd/60at/tI6HxzZitVyla5rB8hoPm\n-----END RSA PRIVATE KEY-----" + local sign = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsIm5iZiI6MTcyNzI3NDk4M30.Zvp8dXefvGXrKgeoaNsA3sbV_3fw1w6Te7a0B_UANzef7gGJwvlnD6c3-f4yAy7GPgNzP_H1-atcF-sgLHAYpUa14XKe22a9S_BJSoQszoZuqGgpnGcjSzDMK9JX3FLUtzOFMQR5C4_3d7_z0NlepNo2xdQ6IQj0SvS1jrNwydpA9L89N07id3EO739uNw339g78N9QHP-j8nWItfbjo31xefCWTHtcloGkfaJOhcr06qmSbrivBU1AuPA8T3ZVumqw6fcRJzrvQJdKEfVyP-IPUtUy8SM1yLqstaKojJtU3A2HKaeb4fycwHXxtl52xhzIshr_I3iUhX_ak-z7m0A" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -844,21 +746,17 @@ hello world -=== TEST 37: sign/verify use RS256 algorithm(private_key numbits = 2048,with extra payload) +=== TEST 34: sign/verify use RS256 algorithm(private_key numbits = 2048,with extra payload) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-rs256&payload=%7B%22aaa%22%3A%2211%22%2C%22bb%22%3A%22222%22%7D', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this private_key and payload + -- private_key = "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAv5LHjZ4FxQ9jk6eQGDRtoRwFVkLq+dUBebs97hrzirokVr2B\n+RoxqdLfKAM+AsN2DadawZ2GqlCV9DL0/gz6nWSqTQpWbQ8c7CrF31EkIHUYRzZv\nWy17K3WC9Odk/gM1FVd0HbZ2Rjuqj9ADeeqxnj9npDqKrMODOENy31SqZNerWZsd\ngGkML5JYbX5hbI2L9LREvRU21fDgSfGL6Mw4Naxnnzcvll4yqwrBELSeDZEAt0+e\n/p1dO7moxF+b1pFkh9vQl6zGvnvf8fOqn5ExtLHXVzgx752PHMwmuj9mO1ko6p8F\nOM0JHDnooI+5rwK4j3I27Ho5nnatVWUaxK4U8wIDAQABAoIBAFsFQC73H8KrNyKW\ngI4fit77U0XS8ZXWMKdH4XrZ71DAdDeKPtC+M05+1GxMbhAeEl8WXraTQ8J0G2s1\nMtXqEMDrbUbBXKLghVtoTy91e/a369sZ7/qgN19Eq/30WzWdDIGhVZgwcy2Xd8hw\nitZIPi/z7ChJcE35bsUytseJkJPsWeMJNq4mLbHqMSBQWze/vNvIeGYr2xfqXc6H\nywGWGlk46RI28mOf7PecU0DxFoTBNcntZrpOwaIrTDsC7E6uNvhVbtsneseTlQuj\nihS7DAH72Zx3CXc9+SL3b5QNRD1Rnp+gKM6itjW1yduOj2dS0p8YzcUYNtxnw5Gv\nuLoHwuECgYEA58NhvnHn10YLBEMYxb30tDobdGfOjBSfih8K53+/SJhqF5mv4qZX\nUfw3o5R+CkkrhbZ24yst7wqKFYZ+LfazOqljOPOrBsgIIry/sXBlcbGLCw9MYFfB\nejKTt/xZjqLdDCcEbiSB0L2xNuyF/TZOu8V5Nu55LXKBqeW4yISQ5FkCgYEA05t1\n2cq8gE1jMfGXQNFIpUDG2j4wJXAPqnJZSUF/BICa55mH/HYRKoP2uTSvAnqNrdGt\nsnjnnMA7T+fGogB4STif1POWfj+BTKVa/qhUX9ytH6TeI4aqPXSZdTVEPRfR7bG1\nIB/j2lyPkiNi2VijMx33xqxIaQUUsvxIT95GSisCgYAdaJFylQmSK3UiaVEvZlcy\nt1zcfH+dDtDfueisT216TLzJmdrTq7/Qy2xT+Xe03mwDX4/ea5A8kN3MtXA1bOR5\nQR0yENlW1vMRVVoNrfFxZ9H46UwLvZbzZo+P/RlwHAJolFrfjwpZ7ngaPBEUfFup\nP/mNmt0Ng0YoxNmZuBiaoQKBgQCa2d4RRgpRvdAEYW41UbHetJuQZAfprarZKZrr\nP9HKoq45I6Je/qurOCzZ9ZLItpRtic6Zl16u2AHPhKZYMQ3VT2mvdZ5AvwpI44zG\nZLpx+FR8nrKsvsRf+q6+Ff/c0Uyfq/cHDi84wZmS8PBKa1Hqe1ix+6t1pvEx1eq4\n/8jiRwKBgGOZzt5H5P0v3cFG9EUPXtvf2k81GmZjlDWu1gu5yWSYpqCfYr/K/1Md\ndaQ/YCKTc12SYL7hZ2j+2/dGFXNXwknIyKNj76UxjUpJywWI5mUaXJZJDkLCRvxF\nkk9nWvPorpjjjxaIVN+TkGgDd/60at/tI6HxzZitVyla5rB8hoPm\n-----END RSA PRIVATE KEY-----" + -- payload = {"aaa":"11","bb":"222"} + local sign = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1yczI1NiIsIm5iZiI6MTcyNzI3NDk4M30.Zvp8dXefvGXrKgeoaNsA3sbV_3fw1w6Te7a0B_UANzef7gGJwvlnD6c3-f4yAy7GPgNzP_H1-atcF-sgLHAYpUa14XKe22a9S_BJSoQszoZuqGgpnGcjSzDMK9JX3FLUtzOFMQR5C4_3d7_z0NlepNo2xdQ6IQj0SvS1jrNwydpA9L89N07id3EO739uNw339g78N9QHP-j8nWItfbjo31xefCWTHtcloGkfaJOhcr06qmSbrivBU1AuPA8T3ZVumqw6fcRJzrvQJdKEfVyP-IPUtUy8SM1yLqstaKojJtU3A2HKaeb4fycwHXxtl52xhzIshr_I3iUhX_ak-z7m0A" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -872,7 +770,7 @@ hello world -=== TEST 38: JWT sign with the public key when using the RS256 algorithm +=== TEST 35: JWT sign with the public key when using the RS256 algorithm --- config location /t { content_by_lua_block { @@ -885,7 +783,6 @@ hello world "jwt-auth": { "key": "user-key-rs256", "algorithm": "RS256", - "private_key": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr\n7noq/0ukiZqVQLSJPMOv0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQ==\n-----END PUBLIC KEY-----", "public_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv\n0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7\n+pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL\nwQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF\nIeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb\n2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs\nYvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG\n-----END RSA PRIVATE KEY-----" } } @@ -900,7 +797,7 @@ passed -=== TEST 39: JWT sign and verify RS256 +=== TEST 36: JWT sign and verify RS256 --- config location /t { content_by_lua_block { @@ -932,16 +829,7 @@ passed -=== TEST 40: sign failed ---- request -GET /apisix/plugin/jwt/sign?key=user-key-rs256 ---- error_code: 500 ---- response_body eval -qr/failed to sign jwt/ - - - -=== TEST 41: sanity(algorithm = HS512) +=== TEST 37: sanity(algorithm = HS512) --- config location /t { content_by_lua_block { @@ -962,7 +850,7 @@ qr/{"algorithm":"HS512","base64_secret":false,"exp":86400,"key":"123","lifetime_ -=== TEST 42: add consumer with username and plugins use HS512 algorithm +=== TEST 38: add consumer with username and plugins use HS512 algorithm --- config location /t { content_by_lua_block { @@ -990,7 +878,7 @@ passed -=== TEST 43: JWT sign and verify use HS512 algorithm +=== TEST 39: JWT sign and verify use HS512 algorithm --- config location /t { content_by_lua_block { @@ -1022,21 +910,13 @@ passed -=== TEST 44: sign / verify (algorithm = HS512) +=== TEST 40: sign / verify (algorithm = HS512) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-HS512', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + local sign = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1IUzUxMiIsIm5iZiI6MTcyNzI3NDk4M30.emzmjIbFqkRAr55YW5YobdXDxYWiMuUNLPooE5G_bbme1ul19p1dKW7ESrlqvr4BPJRKThm4PnkNC4h9xSJpBQ" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -1050,21 +930,16 @@ hello world -=== TEST 45: sign / verify (algorithm = HS512,with extra payload) +=== TEST 41: sign / verify (algorithm = HS512,with extra payload) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-HS512&payload=%7B%22aaa%22%3A%2211%22%2C%22bb%22%3A%22222%22%7D', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this payload + -- payload = {"aaa":"11","bb":"222"} + local sign = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhYWEiOiIxMSIsImJiIjoiMjIyIiwia2V5IjoidXNlci1rZXktSFM1MTIiLCJuYmYiOjE3MjcyNzQ5ODN9.s6E3-wNJypgJL71MxoyTTHBDeqdrGQddFjkhLlh3ZN6IZwgpFRlFT1_8suQg9dWUDHGQqgejULyLPhmBMIbw2A" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -1078,7 +953,7 @@ hello world -=== TEST 46: test for unsupported algorithm +=== TEST 42: test for unsupported algorithm --- config location /t { content_by_lua_block { @@ -1099,7 +974,7 @@ qr/property "algorithm" validation failed/ -=== TEST 47: wrong format of secret +=== TEST 43: wrong format of secret --- config location /t { content_by_lua_block { @@ -1122,7 +997,7 @@ base64_secret required but the secret is not in base64 format -=== TEST 48: when the exp value is not set, make sure the default value(86400) works +=== TEST 44: when the exp value is not set, make sure the default value(86400) works --- config location /t { content_by_lua_block { @@ -1152,28 +1027,7 @@ passed -=== TEST 49: when the exp value is not set, sign jwt use the default value(86400) ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, body, res_data = t('/apisix/plugin/jwt/sign?key=exp-not-set', - ngx.HTTP_GET) - - local jwt = require("resty.jwt") - local jwt_obj = jwt:load_jwt(res_data) - local exp_in_jwt = jwt_obj.payload.exp - local ngx_time = ngx.time - local use_default_exp = ngx_time() + 86400 - 1 <= exp_in_jwt and exp_in_jwt <= ngx_time() + 86400 - ngx.say(use_default_exp) - } - } ---- response_body -true - - - -=== TEST 50: RS256 without public key +=== TEST 45: RS256 without public key --- config location /t { content_by_lua_block { @@ -1200,7 +1054,7 @@ qr/failed to validate dependent schema for \\"algorithm\\"/ -=== TEST 51: RS256 without private key +=== TEST 46: RS256 without private key --- config location /t { content_by_lua_block { @@ -1222,13 +1076,11 @@ qr/failed to validate dependent schema for \\"algorithm\\"/ ngx.say(body) } } ---- error_code: 400 ---- response_body_like eval -qr/failed to validate dependent schema for \\"algorithm\\"/ +--- error_code: 200 -=== TEST 52: add consumer with username and plugins with public_key, private_key(ES256) +=== TEST 47: add consumer with username and plugins with public_key --- config location /t { content_by_lua_block { @@ -1241,8 +1093,7 @@ qr/failed to validate dependent schema for \\"algorithm\\"/ "jwt-auth": { "key": "user-key-es256", "algorithm": "ES256", - "public_key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9\nq9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==\n-----END PUBLIC KEY-----", - "private_key": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----" + "public_key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9\nq9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==\n-----END PUBLIC KEY-----" } } }]] @@ -1259,7 +1110,7 @@ passed -=== TEST 53: JWT sign and verify use ES256 algorithm(private_key numbits = 512) +=== TEST 48: JWT sign and verify use ES256 algorithm(private_key numbits = 512) --- config location /t { content_by_lua_block { @@ -1293,21 +1144,16 @@ passed -=== TEST 54: sign/verify use ES256 algorithm(private_key numbits = 512) +=== TEST 49: sign/verify use ES256 algorithm(private_key numbits = 512) --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key-es256', - ngx.HTTP_GET - ) - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + -- the jwt signature is encoded with this private_key + -- private_key = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----" + local sign = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleS1lczI1NiIsIm5iZiI6MTcyNzI3NDk4M30.t-CZzJRSxIuVVjU3m8_zDtb7h9x2R2s3BJWmerh0hw-RMIklBqLJ3V9kYAWl7DIyXlp0jQCPDZ_M7mhr1Q3HPw" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -1320,3 +1166,59 @@ passed hello world --- skip_eval 1: $ENV{OPENSSL_FIPS} eq 'yes' + + + +=== TEST 50: add consumer missing public_key (algorithm=RS256) +--- 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": "kerouac", + "plugins": { + "jwt-auth": { + "key": "user-key-res256", + "algorithm": "RS256" + } + } + }]] + ) + + ngx.status = code + ngx.print(body) + } + } +--- error_code: 400 +--- response_body +{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin jwt-auth err: failed to validate dependent schema for \"algorithm\": value should match only one schema, but matches none"} + + + +=== TEST 51: add consumer missing public_key (algorithm=ES256) +--- 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": "kerouac", + "plugins": { + "jwt-auth": { + "key": "user-key-es256", + "algorithm": "ES256" + } + } + }]] + ) + + ngx.status = code + ngx.print(body) + } + } +--- error_code: 400 +--- response_body +{"error_msg":"invalid plugins configuration: failed to check the configuration of plugin jwt-auth err: failed to validate dependent schema for \"algorithm\": value should match only one schema, but matches none"} diff --git a/t/plugin/jwt-auth2.t b/t/plugin/jwt-auth2.t index 412bd04b3613..965771197271 100644 --- a/t/plugin/jwt-auth2.t +++ b/t/plugin/jwt-auth2.t @@ -257,30 +257,18 @@ hello world ngx.say(body) end - -- resgiter jwt sign api - local code, body = t('/apisix/admin/routes/2', - ngx.HTTP_PUT, - [[{ - "plugins": { - "public-api": {} - }, - "uri": "/apisix/plugin/jwt/sign" - }]] - ) - if code >= 300 then - ngx.status = code - ngx.say(body) - end - - -- get JWT token - local code, err, sign = t('/apisix/plugin/jwt/sign?key=test-jwt-a', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return + local gen_token = require("lib.apisix.plugins.jwt-auth").gen_token + local auth_conf = { + exp = 1, + algorithm = "HS256", + base64_secret = false, + secret = "test-jwt-secret", + key = "test-jwt-a" + } + local sign = gen_token(auth_conf) + if not sign then + ngx.status = 500 + ngx.say("failed to gen_token") end -- verify JWT token @@ -423,30 +411,20 @@ qr/ailed to verify jwt: 'exp' claim expired at/ ngx.say(body) end - -- resgiter jwt sign api - local code, body = t('/apisix/admin/routes/2', - ngx.HTTP_PUT, - [[{ - "plugins": { - "public-api": {} - }, - "uri": "/apisix/plugin/jwt/sign" - }]] - ) - if code >= 300 then - ngx.status = code - ngx.say(body) - end - -- get JWT token - local code, err, sign = t('/apisix/plugin/jwt/sign?key=test-jwt-a', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return + local gen_token = require("lib.apisix.plugins.jwt-auth").gen_token + local auth_conf = { + exp = 1, + algorithm = "HS256", + base64_secret = false, + secret = "test-jwt-secret", + key = "test-jwt-a", + lifetime_grace_period = 2 + } + local sign = gen_token(auth_conf) + if not sign then + ngx.status = 500 + ngx.say("failed to gen_token") end -- verify JWT token diff --git a/t/plugin/jwt-auth3.t b/t/plugin/jwt-auth3.t index c28fad3075a7..0c0d33a902b3 100755 --- a/t/plugin/jwt-auth3.t +++ b/t/plugin/jwt-auth3.t @@ -378,78 +378,7 @@ IRWpPjbDq5BCgHyIllnOMA== -=== TEST 15: data encryption for private_key ---- yaml_config -apisix: - data_encryption: - enable_encrypt_fields: true - keyring: - - edd1c9f0985e76a2 ---- config - location /t { - content_by_lua_block { - local json = require("toolkit.json") - local t = require("lib.test_admin").test - - -- dletet exist consumers - t('/apisix/admin/consumers/jack', ngx.HTTP_DELETE) - - local code, body = t('/apisix/admin/consumers', - ngx.HTTP_PUT, - [[{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "user-key-rs256", - "algorithm": "RS256", - "public_key": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr\n7noq/0ukiZqVQLSJPMOv0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQ==\n-----END PUBLIC KEY-----", - "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv\n0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7\n+pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL\nwQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF\nIeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb\n2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs\nYvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG\n-----END RSA PRIVATE KEY-----" - } - } - }]] - ) - - if code >= 300 then - ngx.status = code - ngx.say(body) - return - end - ngx.sleep(0.1) - - -- get plugin conf from admin api, password is decrypted - local code, message, res = t('/apisix/admin/consumers/jack', - ngx.HTTP_GET - ) - res = json.decode(res) - if code >= 300 then - ngx.status = code - ngx.say(message) - return - end - - ngx.say(res.value.plugins["jwt-auth"].private_key) - - -- get plugin conf from etcd, password is encrypted - local etcd = require("apisix.core.etcd") - local res = assert(etcd.get('/consumers/jack')) - ngx.say(res.body.node.value.plugins["jwt-auth"].private_key) - } - } ---- response_body ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAKebDxlvQMGyEesAL1r1nIJBkSdqu3Hr7noq/0ukiZqVQLSJPMOv -0oxQSutvvK3hoibwGakDOza+xRITB7cs2cECAwEAAQJAYPWh6YvjwWobVYC45Hz7 -+pqlt1DWeVQMlN407HSWKjdH548ady46xiQuZ5Cfx3YyCcnsfVWaQNbC+jFbY4YL -wQIhANfASwz8+2sKg1xtvzyaChX5S5XaQTB+azFImBJumixZAiEAxt93Td6JH1RF -IeQmD/K+DClZMqSrliUzUqJnCPCzy6kCIAekDsRh/UF4ONjAJkKuLedDUfL3rNFb -2M4BBSm58wnZAiEAwYLMOg8h6kQ7iMDRcI9I8diCHM8yz0SfbfbsvzxIFxECICXs -YvIufaZvBa8f+E/9CANlVhm5wKAyM8N8GJsiCyEG ------END RSA PRIVATE KEY----- -HrMHUvE9Esvn7GnZ+vAynaIg/8wlB3r0zm0htmnwofYPZeBpLnpW3iN9UtQG4ZIBYRZih6EBuRK8W3Kychw/SgjIFuzVeTFowBCUfd1wZ4Q+frUOLZ0Xmkh8j3yHUprnh+d9PA8EHCEapdkWY3psJj6rTgrREzjDEVf/TV3EjjfgG16ih5/c3TChApLXwfEwfBp5APSf7kzMccCRbA4bXvMDsQSQAwVsRD8cjJkSdHTvuzfg1g8xoCy4I05DsMM8CybJAd+BDZnJxhrGIQaItu5/0XQJy+uy/niOpzYYN+NDX+8fl65VUxdUtqXF82ChRlmGP3+zKN7epufAsL/36pHOnS73Q7WBKRxyyA16BEBk0wK7rI+KemBfG5YFXjcBnPkxYssSudqhmlcr6e5Tl0LhVj/BIj94fVE3/EJ+NO3BJMrlhjorilrQKAsiCWujWSqAK7gtAp3YEO//yOygh/p8gh22NdIV0ykGAx4QNKINUgdgh+g8DdykNGLGStH8TPUs8GmzV7nxvw/0cbiocLps6uk0VjjVUqUAvOdwpbiRwv6effPUB6cxW3G6QllBbTP8I+eoFIRfYd6cFJPpX1AtISfNZw459WarwZmHrZGOQU4iKlyl2yLcKY634Fx5JykUY5YP+MYYDHbIcD2gxA== - - - -=== TEST 16: set jwt-auth conf: secret uses secret ref +=== TEST 15: set jwt-auth conf: secret uses secret ref --- request GET /t --- config @@ -522,7 +451,7 @@ passed -=== TEST 17: store secret into vault +=== TEST 16: store secret into vault --- exec VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack secret=my-secret-key --- response_body @@ -530,7 +459,7 @@ Success! Data written to: kv/apisix/jack -=== TEST 18: verify (in header) not hiding credentials +=== TEST 17: verify (in header) not hiding credentials --- request GET /echo --- more_headers @@ -540,15 +469,15 @@ jwt-header: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIs -=== TEST 19: store rsa key pairs and secret into vault from local filesystem +=== TEST 18: store rsa key pairs and secret into vault from local filesystem --- exec -VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/rsa1 secret=$3nsitiv3-c8d3 public_key=@t/certs/public.pem private_key=@t/certs/private.pem +VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/rsa1 secret=$3nsitiv3-c8d3 public_key=@t/certs/public.pem --- response_body Success! Data written to: kv/apisix/rsa1 -=== TEST 20: create consumer for RS256 algorithm with private/public key fetched from vault and public key in consumer schema +=== TEST 19: create consumer for RS256 algorithm with public key fetched from vault and public key in consumer schema --- config location /t { content_by_lua_block { @@ -575,22 +504,6 @@ Success! Data written to: kv/apisix/rsa1 return ngx.say(body) end - -- create public API route (jwt-auth sign) - local code, body = t('/apisix/admin/routes/2', - ngx.HTTP_PUT, - [[{ - "plugins": { - "public-api": {} - }, - "uri": "/apisix/plugin/jwt/sign" - }]] - ) - - if code >= 300 then - ngx.status = code - return ngx.say(body) - end - local code, body = t('/apisix/admin/consumers', ngx.HTTP_PUT, [[{ @@ -600,8 +513,7 @@ Success! Data written to: kv/apisix/rsa1 "key": "rsa1", "algorithm": "RS256", "secret": "$secret://vault/test1/rsa1/secret", - "public_key": "$secret://vault/test1/rsa1/public_key", - "private_key": "$secret://vault/test1/rsa1/private_key" + "public_key": "$secret://vault/test1/rsa1/public_key" } } }]] @@ -618,36 +530,7 @@ passed -=== TEST 21: sign a jwt with with rsa key pair and access /hello ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=rsa1', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/hello?jwt=' .. sign, - ngx.HTTP_GET - ) - if code >= 300 then - ngx.status = code - end - ngx.print(res) - } - } ---- response_body -hello world - - - -=== TEST 22: set jwt-auth conf with the token in an env var: secret uses secret ref +=== TEST 20: set jwt-auth conf with the token in an env var: secret uses secret ref --- request GET /t --- config @@ -716,7 +599,7 @@ passed -=== TEST 23: verify (in header) not hiding credentials +=== TEST 21: verify (in header) not hiding credentials --- request GET /echo --- more_headers diff --git a/t/plugin/jwt-auth4.t b/t/plugin/jwt-auth4.t deleted file mode 100644 index f91b233f4c4f..000000000000 --- a/t/plugin/jwt-auth4.t +++ /dev/null @@ -1,122 +0,0 @@ -# -# 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. -# -BEGIN { - $ENV{VAULT_TOKEN} = "root"; -} - -use t::APISIX 'no_plan'; - -repeat_each(1); -no_long_string(); -no_root_location(); -no_shuffle(); - -add_block_preprocessor(sub { - my ($block) = @_; - - if ((!defined $block->error_log) && (!defined $block->no_error_log)) { - $block->set_value("no_error_log", "[error]"); - } - - if (!defined $block->request) { - $block->set_value("request", "GET /t"); - if (!$block->response_body) { - $block->set_value("response_body", "passed\n"); - } - } -}); - -run_tests; - -__DATA__ - -=== TEST 1: verify the real_payload's value (key & exp) is not overridden by malicious payload ---- config - location /t { - content_by_lua_block { - local core = require("apisix.core") - local t = require("lib.test_admin").test - - -- prepare consumer - local csm_code, csm_body = t('/apisix/admin/consumers', - ngx.HTTP_PUT, - [[{ - "username": "jack", - "plugins": { - "jwt-auth": { - "key": "user-key", - "secret": "my-secret-key" - } - } - }]] - ) - - if csm_code >= 300 then - ngx.status = csm_code - ngx.say(csm_body) - return - end - - -- prepare sign api - local rot_code, rot_body = t('/apisix/admin/routes/2', - ngx.HTTP_PUT, - [[{ - "plugins": { - "public-api": {} - }, - "uri": "/apisix/plugin/jwt/sign" - }]] - ) - - if rot_code >= 300 then - ngx.status = rot_code - ngx.say(rot_body) - return - end - - -- generate jws - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key&payload={"key":"letmein","exp":1234567890}', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - -- get payload section from jws - local payload = string.match(sign,"^.+%.(.+)%..+$") - - if not payload then - ngx.say("sign-failed") - return - end - - -- check payload value - local res = core.json.decode(ngx.decode_base64(payload)) - - if res.key == 'user-key' and res.exp ~= 1234567890 then - ngx.say("safe-jws") - return - end - - ngx.say("fake-jws") - } - } ---- response_body -safe-jws diff --git a/t/plugin/multi-auth.t b/t/plugin/multi-auth.t index aacfe200f7e9..2bb3babb8a26 100644 --- a/t/plugin/multi-auth.t +++ b/t/plugin/multi-auth.t @@ -485,35 +485,7 @@ qr/\{"error_msg":"failed to check the configuration of plugin multi-auth err: pr -=== TEST 19: create public API route (jwt-auth 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/jwt/sign" - }]] - ) - - if code >= 300 then - ngx.status = code - end - ngx.say(body) - } - } ---- request -GET /t ---- response_body -passed - - - -=== TEST 20: add consumer with username and jwt-auth plugins +=== TEST 19: add consumer with username and jwt-auth plugins --- config location /t { content_by_lua_block { @@ -544,21 +516,13 @@ passed -=== TEST 21: sign / verify jwt-auth +=== TEST 20: sign / verify jwt-auth --- config location /t { content_by_lua_block { local t = require("lib.test_admin").test - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end + local sign = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30.N6ebc4U5ms976pwKZ_iQ88w_uJKqUVNtTYZ_nXhRpWo" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) @@ -574,7 +538,7 @@ hello world -=== TEST 22: verify multi-auth with plugin config will cause the conf_version change +=== TEST 21: verify multi-auth with plugin config will cause the conf_version change --- config location /t { content_by_lua_block { @@ -634,16 +598,7 @@ hello world end ngx.sleep(0.1) - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - + local sign = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsIm5iZiI6MTcyNzI3NDk4M30.N6ebc4U5ms976pwKZ_iQ88w_uJKqUVNtTYZ_nXhRpWo" local code, _, res = t('/hello?jwt=' .. sign, ngx.HTTP_GET ) diff --git a/t/plugin/plugin.t b/t/plugin/plugin.t index 28fd81868483..53c87b0b5133 100644 --- a/t/plugin/plugin.t +++ b/t/plugin/plugin.t @@ -114,31 +114,7 @@ passed content_by_lua_block { local t = require("lib.test_admin").test - local code, err = t('/apisix/admin/routes/jwt', - ngx.HTTP_PUT, - [[{ - "uri": "/apisix/plugin/jwt/sign", - "plugins": { "public-api": {} } - }]] - ) - - if code >= 300 then - ngx.status = code - ngx.say(err) - return - end - - local code, err, sign = t('/apisix/plugin/jwt/sign?key=user-key', - ngx.HTTP_GET - ) - - if code > 200 then - ngx.status = code - ngx.say(err) - return - end - - local code, _, res = t('/hello?jwt=' .. sign, + local code, _, res = t('/hello?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0.fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs', ngx.HTTP_GET ) diff --git a/t/plugin/public-api.t b/t/plugin/public-api.t index dab4f10a9357..6b4c9f3c7e7b 100644 --- a/t/plugin/public-api.t +++ b/t/plugin/public-api.t @@ -37,7 +37,7 @@ __DATA__ location /t { content_by_lua_block { local test_cases = { - {uri = "/apisix/plugin/jwt/sign"}, + {uri = "/apisix/plugin/wolf-rbac/user_info"}, {uri = 3233} } local plugin = require("apisix.plugins.public-api") @@ -71,21 +71,6 @@ property "uri" validation failed: wrong type: expected string, got number } }]] }, - { - uri = "/apisix/admin/routes/custom-jwt-sign", - data = [[{ - "plugins": { - "public-api": { - "uri": "/apisix/plugin/jwt/sign" - }, - "serverless-pre-function": { - "phase": "rewrite", - "functions": ["return function(conf, ctx) require(\"apisix.core\").log.warn(\"custom-jwt-sign was triggered\"); end"] - } - }, - "uri": "/gen_token" - }]], - }, { uri = "/apisix/admin/routes/direct-wolf-rbac-userinfo", data = [[{ @@ -121,38 +106,11 @@ property "uri" validation failed: wrong type: expected string, got number } } --- response_body eval -"201passed\n" x 4 - - - -=== TEST 3: hit route (custom-jwt-sign) ---- config - location /t { - content_by_lua_block { - local t = require("lib.test_admin").test - - local code, body, jwt = t("/gen_token?key=user-key", ngx.HTTP_GET, "", nil, {apikey = "testkey"}) - if code >= 300 then - ngx.status = code - end - - local header = string.sub(jwt, 1, 36) - - if header == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" or - header == "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" then - ngx.say("passed") - return - end - - ngx.say("failed") - } - } ---- response_body -passed +"201passed\n" x 3 -=== TEST 4: hit route (direct-wolf-rbac-userinfo) +=== TEST 3: hit route (direct-wolf-rbac-userinfo) --- request GET /apisix/plugin/wolf-rbac/user_info --- error_code: 401 @@ -161,21 +119,21 @@ direct-wolf-rbac-userinfo was triggered -=== TEST 5: missing route (non-exist public API) +=== TEST 4: missing route (non-exist public API) --- request GET /apisix/plugin/balalbala --- error_code: 404 -=== TEST 6: hit route (wrong public-api uri) +=== TEST 5: hit route (wrong public-api uri) --- request GET /wrong-public-api --- error_code: 404 -=== TEST 7: setup route (protect public API) +=== TEST 6: setup route (protect public API) --- config location /t { content_by_lua_block { @@ -192,15 +150,19 @@ GET /wrong-public-api }]] }, { - uri = "/apisix/admin/routes/custom-jwt-sign", + uri = "/apisix/admin/routes/custom-user-info", data = [[{ "plugins": { "public-api": { - "uri": "/apisix/plugin/jwt/sign" + "uri": "/apisix/plugin/wolf-rbac/user_info" }, - "key-auth": {} + "key-auth": {}, + "serverless-pre-function": { + "phase": "rewrite", + "functions": ["return function(conf, ctx) require(\"apisix.core\").log.warn(\"direct-wolf-rbac-userinfo was triggered\"); end"] + } }, - "uri": "/gen_token" + "uri": "/get_user_info" }]], } } @@ -215,19 +177,24 @@ GET /wrong-public-api } --- response_body 201passed -200passed +201passed -=== TEST 8: hit route (with key-auth header) +=== TEST 7: hit route (with key-auth header) --- request -GET /gen_token?key=user-key +GET /get_user_info?key=user-key --- more_headers apikey: testkey +--- error_code: 401 +--- error_log +direct-wolf-rbac-userinfo was triggered -=== TEST 9: hit route (without key-auth header) +=== TEST 8: hit route (without key-auth header) --- request -GET /gen_token?key=user-key +GET /get_user_info?key=user-key --- error_code: 401 +--- response_body +{"message":"Missing API key in request"}