forked from alibaba/higress
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
1,255 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Copyright (c) 2022 Alibaba Group Holding Ltd. | ||
# | ||
# Licensed 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. | ||
|
||
load("@proxy_wasm_cpp_sdk//bazel:defs.bzl", "proxy_wasm_cc_binary") | ||
load("//bazel:wasm.bzl", "declare_wasm_image_targets") | ||
|
||
proxy_wasm_cc_binary( | ||
name = "oauth.wasm", | ||
srcs = [ | ||
"plugin.cc", | ||
"plugin.h", | ||
], | ||
deps = [ | ||
"//common:random_util", | ||
"@com_github_thalhammer_jwt_cpp//:lib", | ||
"@com_github_mariusbancila_stduuid//:lib", | ||
"@com_google_absl//absl/container:btree", | ||
"@com_google_absl//absl/strings", | ||
"@com_google_absl//absl/strings:str_format", | ||
"@com_google_absl//absl/time", | ||
"@boringssl//:ssl", | ||
"//common:json_util", | ||
"//common:http_util", | ||
"//common:rule_util", | ||
], | ||
) | ||
|
||
cc_library( | ||
name = "oauth_lib", | ||
srcs = [ | ||
"plugin.cc", | ||
], | ||
hdrs = [ | ||
"plugin.h", | ||
], | ||
copts = ["-DNULL_PLUGIN"], | ||
deps = [ | ||
"@com_github_thalhammer_jwt_cpp//:lib", | ||
"@com_github_mariusbancila_stduuid//:lib", | ||
"@com_google_absl//absl/container:btree", | ||
"@com_google_absl//absl/strings", | ||
"@com_google_absl//absl/strings:str_format", | ||
"@com_google_absl//absl/time", | ||
"@boringssl//:ssl", | ||
"//common:json_util", | ||
"@proxy_wasm_cpp_host//:lib", | ||
"//common:http_util_nullvm", | ||
"//common:rule_util_nullvm", | ||
], | ||
) | ||
|
||
cc_test( | ||
name = "oauth_test", | ||
srcs = [ | ||
"plugin_test.cc", | ||
], | ||
copts = ["-DNULL_PLUGIN"], | ||
deps = [ | ||
":oauth_lib", | ||
"@com_google_googletest//:gtest", | ||
"@com_google_googletest//:gtest_main", | ||
"@proxy_wasm_cpp_host//:lib", | ||
], | ||
) | ||
|
||
declare_wasm_image_targets( | ||
name = "oauth", | ||
wasm_file = ":oauth.wasm", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# 功能说明 | ||
`OAuth2`插件实现了基于JWT(JSON Web Tokens)进行OAuth2 Access Token签发的能力, 遵循[RFC9068](https://datatracker.ietf.org/doc/html/rfc9068)规范 | ||
|
||
# 插件配置说明 | ||
|
||
## 配置字段 | ||
|
||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| ----------- | --------------- | ------------------------------------------- | ------ | ----------------------------------------------------------- | | ||
| `consumers` | array of object | 必填 | - | 配置服务的调用者,用于对请求进行认证 | | ||
| `_rules_` | array of object | 选填 | - | 配置特定路由或域名的访问权限列表,用于对请求进行鉴权 | | ||
| `issuer` | string | 选填 | Higress-Gateway | 用于填充JWT中的issuer | | ||
| `auth_path` | string | 选填 | /oauth2/token | 指定路径后缀用于签发Token,路由级配置时,要确保首先能匹配对应的路由 | | ||
| `global_credentials` | bool | 选填 | ture | 是否开启全局凭证,即允许路由A下的auth_path签发的Token可以用于访问路由B | | ||
| `auth_header_name` | string | 选填 | Authorization | 用于指定从哪个请求头获取JWT | | ||
| `token_ttl` | number | 选填 | 7200 | token从签发后多久内有效,单位为秒 | | ||
| `clock_skew_seconds` | number | 选填 | 60 | 校验JWT的exp和iat字段时允许的时钟偏移量,单位为秒 | | ||
| `keep_token` | bool | 选填 | ture | 转发给后端时是否保留JWT | | ||
|
||
`consumers`中每一项的配置字段说明如下: | ||
|
||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| ----------------------- | ----------------- | -------- | ------------------------------------------------- | ------------------------ | | ||
| `name` | string | 必填 | - | 配置该consumer的名称 | | ||
| `client_id` | string | 必填 | - | OAuth2 client id | | ||
| `client_secret` | string | 必填 | - | OAuth2 client secret | | ||
|
||
`_rules_` 中每一项的配置字段说明如下: | ||
|
||
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 | | ||
| ---------------- | --------------- | ------------------------------------------------- | ------ | -------------------------------------------------- | | ||
| `_match_route_` | array of string | 选填,`_match_route_`,`_match_domain_`中选填一项 | - | 配置要匹配的路由名称 | | ||
| `_match_domain_` | array of string | 选填,`_match_route_`,`_match_domain_`中选填一项 | - | 配置要匹配的域名 | | ||
| `allow` | array of string | 必填 | - | 对于符合匹配条件的请求,配置允许访问的consumer名称 | | ||
|
||
**注意:** | ||
- 对于开启该配置的路由,如果路径后缀和`auth_path`匹配,则该路由到原目标服务,而是用于生成Token | ||
- 如果关闭`global_credentials`,请确保启用此插件的路由不是精确匹配路由,此时若存在另一条前缀匹配路由,则可能导致预期外行为 | ||
- 若不配置`_rules_`字段,则默认对当前网关实例的所有路由开启认证; | ||
- 对于通过认证鉴权的请求,请求的header会被添加一个`X-Mse-Consumer`字段,用以标识调用者的名称。 | ||
|
||
## 配置示例 | ||
|
||
### 对特定路由或域名开启 | ||
|
||
以下配置将对网关特定路由或域名开启 Jwt Auth 认证和鉴权,注意如果一个JWT能匹配多个`jwks`,则按照配置顺序命中第一个匹配的`consumer` | ||
|
||
```yaml | ||
consumers: | ||
- name: consumer1 | ||
client_id: 12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
client_secret: abcdefgh-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
- name: consumer2 | ||
client_id: 87654321-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
client_secret: hgfedcba-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
# 使用 _rules_ 字段进行细粒度规则配置 | ||
_rules_: | ||
# 规则一:按路由名称匹配生效 | ||
- _match_route_: | ||
- route-a | ||
- route-b | ||
allow: | ||
- consumer1 | ||
# 规则二:按域名匹配生效 | ||
- _match_domain_: | ||
- "*.example.com" | ||
- test.com | ||
allow: | ||
- consumer2 | ||
``` | ||
此例 `_match_route_` 中指定的 `route-a` 和 `route-b` 即在创建网关路由时填写的路由名称,当匹配到这两个路由时,将允许`name`为`consumer1`的调用者访问,其他调用者不允许访问; | ||
|
||
此例 `_match_domain_` 中指定的 `*.example.com` 和 `test.com` 用于匹配请求的域名,当发现域名匹配时,将允许`name`为`consumer2`的调用者访问,其他调用者不允许访问。 | ||
|
||
#### 使用 Client Credential 授权模式 | ||
|
||
**获取 AccessToken** | ||
|
||
```bash | ||
# 通过 GET 方法获取 | ||
curl 'http://test.com/oauth2/token?grant_type=client_credentials&client_id=12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx&client_secret=abcdefgh-xxxx-xxxx-xxxx-xxxxxxxxxxxx' | ||
# 通过 POST 方法获取 (需要先匹配到有真实目标服务的路由) | ||
curl 'http://test.com/oauth2/token' -H 'content-type: application/x-www-form-urlencoded' -d 'grant_type=client_credentials&client_id=12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx&client_secret=abcdefgh-xxxx-xxxx-xxxx-xxxxxxxxxxxx' | ||
# 获取响应中的 access_token 字段即可: | ||
{ | ||
"token_type": "bearer", | ||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImFwcGxpY2F0aW9uXC9hdCtqd3QifQ.eyJhdWQiOiJkZWZhdWx0IiwiY2xpZW50X2lkIjoiMTIzNDU2NzgteHh4eC14eHh4LXh4eHgteHh4eHh4eHh4eHh4IiwiZXhwIjoxNjg3OTUxNDYzLCJpYXQiOjE2ODc5NDQyNjMsImlzcyI6IkhpZ3Jlc3MtR2F0ZXdheSIsImp0aSI6IjEwOTU5ZDFiLThkNjEtNGRlYy1iZWE3LTk0ODEwMzc1YjYzYyIsInN1YiI6ImNvbnN1bWVyMSJ9.NkT_rG3DcV9543vBQgneVqoGfIhVeOuUBwLJJ4Wycb0", | ||
"expires_in": 7200 | ||
} | ||
``` | ||
|
||
**使用 AccessToken 请求** | ||
|
||
```bash | ||
curl 'http://test.com' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6ImFwcGxpY2F0aW9uXC9hdCtqd3QifQ.eyJhdWQiOiJkZWZhdWx0IiwiY2xpZW50X2lkIjoiMTIzNDU2NzgteHh4eC14eHh4LXh4eHgteHh4eHh4eHh4eHh4IiwiZXhwIjoxNjg3OTUxNDYzLCJpYXQiOjE2ODc5NDQyNjMsImlzcyI6IkhpZ3Jlc3MtR2F0ZXdheSIsImp0aSI6IjEwOTU5ZDFiLThkNjEtNGRlYy1iZWE3LTk0ODEwMzc1YjYzYyIsInN1YiI6ImNvbnN1bWVyMSJ9.NkT_rG3DcV9543vBQgneVqoGfIhVeOuUBwLJJ4Wycb0' | ||
``` | ||
因为 test.com 仅授权了 consumer2,但这个 Access Token 是基于 consumer1 的 `client_id`,`client_secret` 获取的,因此将返回 `403 Access Denied` | ||
|
||
|
||
### 网关实例级别开启 | ||
|
||
以下配置未指定`_rules_`字段,因此将对网关实例级别开启 OAuth2 认证 | ||
|
||
```yaml | ||
consumers: | ||
- name: consumer1 | ||
client_id: 12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
client_secret: abcdefgh-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
- name: consumer2 | ||
client_id: 87654321-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
client_secret: hgfedcba-xxxx-xxxx-xxxx-xxxxxxxxxxxx | ||
``` | ||
|
||
# 常见错误码说明 | ||
|
||
| HTTP 状态码 | 出错信息 | 原因说明 | | ||
| ----------- | ---------------------- | -------------------------------------------------------------------------------- | | ||
| 401 | Invalid Jwt token | 请求头未提供JWT, 或者JWT格式错误,或过期等原因 | | ||
| 403 | Access Denied | 无权限访问当前路由 | | ||
|
Oops, something went wrong.