Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Jwt-auth plugin no longer requires a private_key to be uploaded. #11597

Merged
merged 31 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ef2067a
feat: remove /jwt/sign
dspo Sep 23, 2024
36ca4d0
Merge remote-tracking branch 'origin/master' into dspo/remove-jwt-sign
dspo Sep 23, 2024
cffae79
fix tests
dspo Sep 23, 2024
ed0f740
fix tests
dspo Sep 23, 2024
fdf7b09
typo
dspo Sep 23, 2024
b6492b8
fix tests index
dspo Sep 24, 2024
1fbeaef
reindex
dspo Sep 24, 2024
7d116ee
refactor document
dspo Sep 24, 2024
d4cefb1
jwt-auth plugin no longer need private_key
dspo Sep 24, 2024
7de6736
reindex
dspo Sep 24, 2024
36b5a36
fix unused variable
dspo Sep 24, 2024
c08f917
fix lint
dspo Sep 24, 2024
4398e9e
set default fields values in gen_token
dspo Sep 24, 2024
b399a55
fix tests
dspo Sep 24, 2024
f11dec5
fix test_http.py
dspo Sep 24, 2024
45002a3
remove 1 line comment
dspo Sep 25, 2024
544174b
refactor gen_token
dspo Sep 25, 2024
e1e1c3f
remove useless comment
dspo Sep 25, 2024
21bb26c
typo
dspo Sep 25, 2024
bccbeda
Update apisix/plugins/jwt-auth.lua
dspo Sep 25, 2024
5971c56
batch-requests plugin API as the public-api example
dspo Sep 25, 2024
9f0c3f3
remove redundant schema validation
dspo Sep 25, 2024
80a7c7f
remove code for test from jwt-auth.lua
dspo Sep 25, 2024
46cb2d3
gen_jwt_token locally in test_http.py
dspo Sep 25, 2024
fcc286b
update document: remove descriptions about private_key
dspo Sep 25, 2024
92cc273
lint doc
dspo Sep 25, 2024
9c9b0cf
Instead of using a local jwt library to generate jwt tokens, use a th…
dspo Sep 25, 2024
c558a03
merge origin/master
dspo Sep 27, 2024
fa8bf89
add test cases to test jwt-auth schema
dspo Sep 27, 2024
3ad1c3a
comment that why needs private_key in test cases
dspo Sep 27, 2024
ee706a1
comment that why needs payload in test cases
dspo Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 15 additions & 62 deletions apisix/plugins/jwt-auth.lua
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,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"},
nic-6443 marked this conversation as resolved.
Show resolved Hide resolved
},
}
}
},
encrypt_fields = {"secret", "private_key"},
encrypt_fields = {"secret"},
required = {"key"},
}

Expand Down Expand Up @@ -138,14 +137,10 @@ function _M.check_schema(conf, schema_type)
end

if conf.algorithm == "RS256" or conf.algorithm == "ES256" then
nic-6443 marked this conversation as resolved.
Show resolved Hide resolved
-- Possible options are a) public key is missing
-- b) private key is missing
-- Possible options is: public key is missing
nic-6443 marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down Expand Up @@ -235,15 +230,10 @@ 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
if not public_key then
return nil, nil, "missing public key"
else
return nil, nil, "public and private keys are missing"
end
return public_key, private_key
nic-6443 marked this conversation as resolved.
Show resolved Hide resolved
end


Expand All @@ -265,7 +255,7 @@ 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")
return nil, "failed to sign jwt: failed to get auth_secret"
end
local ok, jwt_token = pcall(jwt.sign, _M,
auth_secret,
Expand All @@ -279,7 +269,7 @@ local function sign_jwt_with_HS(key, consumer, payload)
)
if not ok then
core.log.warn("failed to sign jwt, err: ", jwt_token.reason)
core.response.exit(500, "failed to sign jwt")
return nil, "failed to sign jwt"
end
return jwt_token
end
Expand All @@ -291,7 +281,11 @@ local function sign_jwt_with_RS256_ES256(key, consumer, payload)
)
if not public_key then
core.log.error("failed to sign jwt, err: ", err)
core.response.exit(503, "failed to sign jwt")
return nil, "missing public_key"
end
if not private_key then
core.log.error("failed to sign jwt, err: ", err)
return nil, "missing private_key"
end

local ok, jwt_token = pcall(jwt.sign, _M,
Expand All @@ -309,7 +303,7 @@ local function sign_jwt_with_RS256_ES256(key, consumer, payload)
)
if not ok then
core.log.warn("failed to sign jwt, err: ", jwt_token.reason)
core.response.exit(500, "failed to sign jwt")
return nil, "failed to sign jwt"
end
return jwt_token
end
Expand Down Expand Up @@ -387,51 +381,10 @@ 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))

function _M.gen_token(key, consumer, payload)
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,
}
}
return jwt_token
end


Expand Down
15 changes: 8 additions & 7 deletions docs/en/latest/plugin-develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,20 +439,21 @@ 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 wolf-rbac plugin as an example, this plugin registers `POST /apisix/plugin/wolf-rbac/login` to allow a client to login and get the wolf rbac_token:
nic-6443 marked this conversation as resolved.
Show resolved Hide resolved

```lua
local function gen_token()
--...
function wolf_rbac_login()
-- ...
end

function _M.api()
return {
{
methods = {"GET"},
uri = "/apisix/plugin/jwt/sign",
handler = gen_token,
}
methods = {"POST"},
uri = "/apisix/plugin/wolf-rbac/login",
handler = wolf_rbac_login,
},
-- ...
}
end
```
Expand Down
56 changes: 1 addition & 55 deletions docs/en/latest/plugins/jwt-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,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
Expand Down Expand Up @@ -148,53 +140,7 @@ 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:

```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:

```shell
curl -G --data-urlencode 'payload={"uid":10000,"uname":"test"}' http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key -i
```

```
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

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmFtZSI6InRlc3QiLCJ1aWQiOjEwMDAwLCJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTYxOTA3MzgzOX0.jI9-Rpz1gc3u8Y6lZy8I43RXyCu0nSHANCvfn0YZUCY
```
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.

You can now use this token while making requests:

Expand Down
34 changes: 22 additions & 12 deletions docs/en/latest/plugins/public-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/plugin/wolf-rbac/login` for wolf-rbac using the [wolf-rbac](./wolf-rbac.md) Plugin.

:::note

Expand All @@ -46,7 +46,9 @@ 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 [wolf-rbac](./wolf-rbac.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.

Note: 使用 [wolf-rbac](./wolf-rbac.md) 插件的需要一些前提条件 [wolf-rbac](./wolf-rbac.md#pre-requisites)

### Basic usage

Expand All @@ -57,17 +59,19 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r1' \
-H 'X-API-KEY: <api-key>' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/apisix/plugin/jwt/sign",
"uri": "/apisix/plugin/wolf-rbac/login",
"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 rbac_token response:

```shell
curl 'http://127.0.0.1:9080/apisix/plugin/jwt/sign?key=user-key'
curl http://127.0.0.1:9080/apisix/plugin/wolf-rbac/login -i \
-H "Content-Type: application/json" \
-d '{"appid": "restful", "username":"test", "password":"user-password", "authType":1}'
```

### Using custom URI
Expand All @@ -79,10 +83,10 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \
-H 'X-API-KEY: <api-key>' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/gen_token",
"uri": "/wolf-rbac-login",
"plugins": {
"public-api": {
"uri": "/apisix/plugin/jwt/sign"
"uri": "/apisix/plugin/wolf-rbac/login"
}
}
}'
Expand All @@ -91,7 +95,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 http://127.0.0.1:9080/wolf-rbac-login -i \
-H "Content-Type: application/json" \
-d '{"appid": "restful", "username":"test", "password":"user-password", "authType":1}'
```

### Securing the Route
Expand All @@ -103,10 +109,10 @@ curl -X PUT 'http://127.0.0.1:9180/apisix/admin/routes/r2' \
-H 'X-API-KEY: <api-key>' \
-H 'Content-Type: application/json' \
-d '{
"uri": "/gen_token",
"uri": "/wolf-rbac-login",
"plugins": {
"public-api": {
"uri": "/apisix/plugin/jwt/sign"
"uri": "/apisix/plugin/wolf-rbac/login"
},
"key-auth": {}
}
Expand All @@ -116,8 +122,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 http://127.0.0.1:9080/wolf-rbac-login -i \
-H "apikey: test-apikey"
-H "Content-Type: application/json" \
-d '{"appid": "restful", "username":"test", "password":"user-password", "authType":1}'
```

```shell
Expand All @@ -127,7 +135,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 http://127.0.0.1:9080/wolf-rbac-login -i \
-H "Content-Type: application/json" \
-d '{"appid": "restful", "username":"test", "password":"user-password", "authType":1}'
```

```shell
Expand Down
13 changes: 7 additions & 6 deletions docs/zh/latest/plugin-develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,20 +417,21 @@ end

## 注册公共接口

插件可以注册暴露给公网的接口。以 jwt-auth 插件为例,这个插件为了让客户端能够签名,注册了 `GET /apisix/plugin/jwt/sign` 这个接口
插件可以注册暴露给公网的接口。以 wolf-rbac 插件为例,这个插件为了让客户端能够登录获取 wolf rbac_token,注册了 `POST /apisix/plugin/wolf-rbac/login` 等接口

```lua
local function gen_token()
function wolf_rbac_login()
-- ...
end

function _M.api()
return {
{
methods = {"GET"},
uri = "/apisix/plugin/jwt/sign",
handler = gen_token,
}
methods = {"POST"},
uri = "/apisix/plugin/wolf-rbac/login",
handler = wolf_rbac_login,
},
-- ...
}
end
```
Expand Down
Loading
Loading