feat: Added authz-casbin plugin and doc and tests for it (#4710)

Signed-off-by: Rushikesh Tote <rushi.tote@gmail.com>
Co-authored-by: 罗泽轩 <spacewanderlzx@gmail.com>
Co-authored-by: tzssangglass <tzssangglass@gmail.com>
This commit is contained in:
Rushikesh Tote 2021-08-06 09:05:07 +05:30 committed by GitHub
parent 65a2d63717
commit 183351cd9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 903 additions and 9 deletions

View File

@ -89,7 +89,7 @@ jobs:
tar zxvf ${{ steps.branch_env.outputs.fullname }}
- name: Linux Get dependencies
run: sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl
run: sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl libpcre3 libpcre3-dev
- name: Linux Before install
run: sudo ./ci/${{ matrix.os_name }}_runner.sh before_install

View File

@ -0,0 +1,137 @@
--
-- 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 casbin = require("casbin")
local core = require("apisix.core")
local plugin = require("apisix.plugin")
local ngx = ngx
local get_headers = ngx.req.get_headers
local plugin_name = "authz-casbin"
local schema = {
type = "object",
properties = {
model_path = { type = "string" },
policy_path = { type = "string" },
model = { type = "string" },
policy = { type = "string" },
username = { type = "string"}
},
oneOf = {
{required = {"model_path", "policy_path", "username"}},
{required = {"model", "policy", "username"}}
},
additionalProperties = false
}
local metadata_schema = {
type = "object",
properties = {
model = {type = "string"},
policy = {type = "string"},
},
required = {"model", "policy"},
additionalProperties = false
}
local _M = {
version = 0.1,
priority = 2560,
name = plugin_name,
schema = schema,
metadata_schema = metadata_schema
}
function _M.check_schema(conf, schema_type)
if schema_type == core.schema.TYPE_METADATA then
return core.schema.check(metadata_schema, conf)
end
local ok, err = core.schema.check(schema, conf)
if ok then
return true
else
local metadata = plugin.plugin_metadata(plugin_name)
if metadata and metadata.value and conf.username then
return true
end
end
return false, err
end
local casbin_enforcer
local function new_enforcer_if_need(conf)
if conf.model_path and conf.policy_path then
local model_path = conf.model_path
local policy_path = conf.policy_path
if not conf.casbin_enforcer then
conf.casbin_enforcer = casbin:new(model_path, policy_path)
end
return true
end
if conf.model and conf.policy then
local model = conf.model
local policy = conf.policy
if not conf.casbin_enforcer then
conf.casbin_enforcer = casbin:newEnforcerFromText(model, policy)
end
return true
end
local metadata = plugin.plugin_metadata(plugin_name)
if not (metadata and metadata.value.model and metadata.value.policy) then
return nil, "not enough configuration to create enforcer"
end
local modifiedIndex = metadata.modifiedIndex
if not casbin_enforcer or casbin_enforcer.modifiedIndex ~= modifiedIndex then
local model = metadata.value.model
local policy = metadata.value.policy
casbin_enforcer = casbin:newEnforcerFromText(model, policy)
casbin_enforcer.modifiedIndex = modifiedIndex
end
return true
end
function _M.rewrite(conf, ctx)
-- creates an enforcer when request sent for the first time
local ok, err = new_enforcer_if_need(conf)
if not ok then
return 503, {message = err}
end
local path = ctx.var.uri
local method = ctx.var.method
local username = get_headers()[conf.username] or "anonymous"
if conf.casbin_enforcer then
if not conf.casbin_enforcer:enforce(username, path, method) then
return 403, {message = "Access Denied"}
end
else
if not casbin_enforcer:enforce(username, path, method) then
return 403, {message = "Access Denied"}
end
end
end
return _M

View File

@ -99,6 +99,9 @@ t/toolkit
# Exclude subcomponents files
apisix/balancer/ewma.lua
# Exclude plugin-specific configuration files
t/plugin/authz-casbin
[Options]
# Not all code files allow licenses to appear starting at the first character
# of the file. This option tells the scan to allow licenses to appear starting

View File

@ -27,7 +27,7 @@ install_dependencies() {
# install openresty to make apisix's rpm test work
yum install -y yum-utils && yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
yum install -y openresty openresty-debug openresty-openssl111-debug-devel
yum install -y openresty openresty-debug openresty-openssl111-debug-devel pcre pcre-devel
# install luarocks
./utils/linux-install-luarocks.sh

View File

@ -285,6 +285,7 @@ plugins: # plugin list (sorted by priority)
- uri-blocker # priority: 2900
- request-validation # priority: 2800
- openid-connect # priority: 2599
- authz-casbin # priority: 2560
- wolf-rbac # priority: 2555
- hmac-auth # priority: 2530
- basic-auth # priority: 2520

View File

@ -64,7 +64,8 @@
"plugins/authz-keycloak",
"plugins/wolf-rbac",
"plugins/openid-connect",
"plugins/hmac-auth"
"plugins/hmac-auth",
"plugins/authz-casbin"
]
},
{

View File

@ -58,7 +58,7 @@ sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
# install OpenResty and some compilation tools
sudo yum install -y openresty curl git gcc openresty-openssl111-devel unzip
sudo yum install -y openresty curl git gcc openresty-openssl111-devel unzip pcre pcre-devel
# install LuaRocks
curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -
@ -81,7 +81,7 @@ tar -xvf etcd-v3.4.13-linux-amd64.tar.gz && \
sudo cp -a etcd etcdctl /usr/bin/
# install OpenResty and some compilation tools
sudo yum install -y openresty curl git gcc openresty-openssl111-devel
sudo yum install -y openresty curl git gcc openresty-openssl111-devel pcre pcre-devel
# install LuaRocks
curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -
@ -107,7 +107,7 @@ tar -xvf etcd-v3.4.13-linux-amd64.tar.gz && \
sudo cp -a etcd etcdctl /usr/bin/
# install OpenResty and some compilation tools
sudo apt-get install -y git openresty curl openresty-openssl111-dev make gcc
sudo apt-get install -y git openresty curl openresty-openssl111-dev make gcc libpcre3 libpcre3-dev
# install LuaRocks
curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -
@ -138,7 +138,7 @@ tar -xvf etcd-v3.4.13-linux-amd64.tar.gz && \
sudo cp -a etcd etcdctl /usr/bin/
# install OpenResty and some compilation tools
sudo apt-get install -y git openresty curl make openresty-openssl111-dev
sudo apt-get install -y git openresty curl make openresty-openssl111-dev libpcre3 libpcre3-dev
# install LuaRocks
curl https://raw.githubusercontent.com/apache/apisix/master/utils/linux-install-luarocks.sh -sL | bash -
@ -151,7 +151,7 @@ nohup etcd &
```shell
# install OpenResty, etcd and some compilation tools
brew install openresty/brew/openresty luarocks lua@5.1 etcd curl git
brew install openresty/brew/openresty luarocks lua@5.1 etcd curl git pcre
# start etcd server
brew services start etcd

View File

@ -0,0 +1,250 @@
---
title: authz-casbin
---
<!--
#
# 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.
#
-->
## Summary
- [**Name**](#name)
- [**Attributes**](#attributes)
- [**Metadata**](#metadata)
- [**How To Enable**](#how-to-enable)
- [**Test Plugin**](#test-plugin)
- [**Disable Plugin**](#disable-plugin)
- [**Examples**](#examples)
## Name
`authz-casbin` is an authorization plugin based on [Lua Casbin](https://github.com/casbin/lua-casbin/). This plugin supports powerful authorization scenarios based on various access control models.
For detailed documentation on how to create model and policy, refer [Casbin](https://casbin.org/docs/en/supported-models).
## Attributes
| Name | Type | Requirement | Default | Valid | Description |
| ----------- | ------ | ----------- | ------- | ----- | ------------------------------------------------------------ |
| model_path | string | required | | | The path of the Casbin model configuration file. |
| policy_path | string | required | | | The path of the Casbin policy file. |
| model | string | required | | | The Casbin model configuration in text format. |
| policy | string | required | | | The Casbin policy in text format. |
| username | string | required | | | The header you will be using in request to pass the username (subject). |
**NOTE**: You must either specify `model_path`, `policy_path` and `username` in plugin config or specify `model`, `policy` and `username` in the plugin config for the configuration to be valid. Or if you wish to use a global Casbin configuration, you can first specify `model` and `policy` in the plugin metadata and only `username` in the plugin configuration, all routes will use the plugin metadata configuration in this way.
## Metadata
| Name | Type | Requirement | Default | Valid | Description |
| ----------- | ------ | ----------- | ------- | ----- | ---------------------------------------------------------------------- |
| model | string | required | | | The Casbin model configuration in text format. |
| policy | string | required | | | The Casbin policy in text format. |
## How To Enable
You can enable the plugin on any route either by using the model/policy file paths or directly using the model/policy text.
### By using file paths
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model_path": "/path/to/model.conf",
"policy_path": "/path/to/policy.csv",
"username": "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
```
This will create a Casbin enforcer from the model and policy files at your first request.
### By using model/policy text
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin",
"username": "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
```
This will create a Casbin enforcer from the model and policy text at your first request.
### By using model/policy text using plugin metadata
First, send a `PUT` request to add the model and policy text to the plugin's metadata using the Admin API. All routes configured in this way will use a single Casbin enforcer with plugin metadata configuration. You can also update the model/policy this way, the plugin will automatically update itself with the updated configuration.
```shell
curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/authz-casbin -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -i -X PUT -d '
{
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin"
}'
```
Then add this plugin on a route by sending the following request. Note, there is no requirement for model/policy now.
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"username": "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'
```
**NOTE**: The plugin route configuration has a higher precedence than the plugin metadata configuration. Hence if the model/policy configuration is present in the plugin route config, the plugin will use that instead of the metadata config.
## Test Plugin
We defined the example model as:
```conf
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)
```
And the example policy as:
```conf
p, *, /, GET
p, admin, *, *
g, alice, admin
```
This means that anyone can access the homepage (`/`) using `GET` request method while only users with admin permissions can access other pages and use other request methods.
For example, here anyone can access the homepage with the GET request method and the request proceeds normally:
```shell
curl -i http://127.0.0.1:9080/ -X GET
```
If some unauthorized user `bob` tries to access any other page, they will get a 403 error:
```shell
curl -i http://127.0.0.1:9080/res -H 'user: bob' -X GET
HTTP/1.1 403 Forbidden
```
But someone with admin permissions like `alice`can access it:
```shell
curl -i http://127.0.0.1:9080/res -H 'user: alice' -X GET
```
## Disable Plugin
Remove the corresponding json configuration in the plugin configuration to disable the `authz-casbin` plugin.
APISIX plugins are hot-reloaded, therefore no need to restart APISIX.
```shell
$ curl http://127.0.0.1:2379/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d value='
{
"methods": ["GET"],
"uri": "/*",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}'
```
## Examples
Checkout examples for model and policy conguration [here](https://github.com/casbin/lua-casbin/tree/master/examples).

View File

@ -67,6 +67,7 @@ dependencies = {
"lua-resty-consul = 0.3-2",
"penlight = 1.9.2-1",
"ext-plugin-proto = 0.2.1",
"casbin = 1.26.0",
}
build = {

2
t/admin/plugins.t vendored
View File

@ -40,7 +40,7 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
qr/\["client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/
qr/\["client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","ua-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","authz-casbin","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","gzip","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/
--- no_error_log
[error]

484
t/plugin/authz-casbin.t vendored Normal file
View File

@ -0,0 +1,484 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
no_long_string();
no_root_location();
run_tests;
__DATA__
=== TEST 1: sanity
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.authz-casbin")
local conf = {
model_path = "/path/to/model.conf",
policy_path = "/path/to/policy.csv",
username = "user"
}
local ok, err = plugin.check_schema(conf)
if not ok then
ngx.say(err)
end
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
--- no_error_log
[error]
=== TEST 2: username missing
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.authz-casbin")
local conf = {
model_path = "/path/to/model.conf",
policy_path = "/path/to/policy.csv"
}
local ok, err = plugin.check_schema(conf)
if not ok then
ngx.say(err)
else
ngx.say("done")
end
}
}
--- request
GET /t
--- response_body
value should match only one schema, but matches none
--- no_error_log
[error]
=== TEST 3: put model and policy text in metadata
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.authz-casbin")
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/authz-casbin',
ngx.HTTP_PUT,
[[{
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin"
}]]
)
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 4: Enforcer from text without files
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.authz-casbin")
local t = require("lib.test_admin").test
local conf = {
username = "user"
}
local ok, err = plugin.check_schema(conf)
if not ok then
ngx.say(err)
end
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
--- no_error_log
[error]
=== TEST 5: enable authz-casbin by Admin API
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"authz-casbin": {
"username" : "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 6: no username header passed
--- request
GET /hello
--- error_code: 403
--- response_body_like eval
qr/"Access Denied"/
--- no_error_log
[error]
=== TEST 7: username passed but user not authorized
--- request
GET /hello
--- more_headers
user: bob
--- error_code: 403
--- response_body
{"message":"Access Denied"}
--- no_error_log
[error]
=== TEST 8: authorized user
--- request
GET /hello
--- more_headers
user: admin
--- error_code: 200
--- response_body
hello world
--- no_error_log
[error]
=== TEST 9: authorized user (rbac)
--- request
GET /hello
--- more_headers
user: alice
--- error_code: 200
--- response_body
hello world
--- no_error_log
[error]
=== TEST 10: unauthorized user before policy update
--- request
GET /hello
--- more_headers
user: jack
--- error_code: 403
--- response_body
{"message":"Access Denied"}
--- no_error_log
[error]
=== TEST 11: update model and policy text in metadata
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.authz-casbin")
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/plugin_metadata/authz-casbin',
ngx.HTTP_PUT,
[[{
"model": "[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "p, *, /, GET
p, admin, *, *
p, jack, /hello, GET
g, alice, admin"
}]]
)
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 12: authorized user after policy update
--- request
GET /hello
--- more_headers
user: jack
--- error_code: 200
--- response_body
hello world
--- no_error_log
[error]
=== TEST 13: enable authz-casbin using model/policy files
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"authz-casbin": {
"model_path": "t/plugin/authz-casbin/model.conf",
"policy_path": "t/plugin/authz-casbin/policy.csv",
"username" : "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 14: authorized user as per policy
--- request
GET /hello
--- more_headers
user: alice
--- error_code: 200
--- response_body
hello world
--- no_error_log
[error]
=== TEST 15: unauthorized user as per policy
--- request
GET /hello
--- more_headers
user: bob
--- error_code: 403
--- response_body
{"message":"Access Denied"}
--- no_error_log
[error]
=== TEST 16: enable authz-casbin using model/policy text
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"authz-casbin": {
"model": "
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",
"policy": "
p, *, /, GET
p, admin, *, *
g, jack, admin",
"username" : "user"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
=== TEST 17: authorized user as per policy
--- request
GET /hello
--- more_headers
user: jack
--- error_code: 200
--- response_body
hello world
--- no_error_log
[error]
=== TEST 18: unauthorized user as per policy
--- request
GET /hello
--- more_headers
user: bob
--- error_code: 403
--- response_body
{"message":"Access Denied"}
--- no_error_log
[error]
=== TEST 19: disable authz-casbin by Admin API
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {},
"upstream": {
"nodes": {
"127.0.0.1:1982": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]

View File

@ -0,0 +1,14 @@
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)

View File

@ -0,0 +1,3 @@
p, *, /, GET
p, admin, *, *
g, alice, admin
1 p, *, /, GET
2 p, admin, *, *
3 g, alice, admin