Skip to content

访问控制:配置授权模型与正反用例 ​

本篇以访问控制模型为例;前置是可信主体、含租户的资源标识、动作与策略版本。源码与输入与下文配置共用同一份文件,示例未执行。

前置、依赖与输入 ​

访问控制完整示例是离线证据处理器,示例未执行。需要Python3.11以上标准库,第三方依赖为零,不需要服务、管理员或网络。输入JSON只含虚构记录,程序不调用系统命令、不建立连接、不修改主机。完整文件位于examples/m5-next-security,必须一起阅读README、lab.py和case.json。

完整源码与配置 ​

下面包括完整源码与全部输入;这不是产品配置验证器,也不执行协议、密码学或系统策略。判断只依据输入声明,不能用输出证明真实环境。

python
"""Offline teaching model. No network, subprocesses, or system mutations."""
import json
from pathlib import Path
import sys


def require(value, schema):
    if type(value) is not dict or set(value) != set(schema):
        raise ValueError("unexpected or missing fields")
    for key, expected in schema.items():
        if type(value[key]) is not expected:
            raise ValueError("wrong field type: " + key)


def decide(row):
    require(row, {"name": str, "subject": str, "object": str, "action": str, "rules": list})
    if not all(row[key] for key in ("subject", "object", "action")):
        raise ValueError("empty request tuple")
    effects = []
    for rule in row["rules"]:
        require(rule, {"subject": str, "object": str, "action": str, "effect": str})
        if rule["effect"] not in ("allow", "deny"):
            raise ValueError("unknown effect")
        if all(row[key] == rule[key] for key in ("subject", "object", "action")):
            effects.append(rule["effect"])
    if "deny" in effects:
        return "DENY_EXPLICIT"
    if "allow" in effects:
        return "ALLOW"
    return "DENY_DEFAULT"


def main(args):
    if len(args) != 1:
        print("usage: python lab.py case.json", file=sys.stderr)
        return 2
    try:
        source = Path(args[0]).read_text(encoding="utf-8")
        data = json.loads(source)
        if type(data) is not list or not data:
            raise ValueError("nonempty list required")
        # Validate every row before publishing any decisions.
        results = [(row, decide(row)) for row in data]
        for row, result in results:
            print(row["name"] + ": " + result)
        return 0
    except (OSError, ValueError, KeyError, TypeError, OverflowError):
        print("invalid input", file=sys.stderr)
        return 2


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1:]))
json
[
  {
    "name": "read",
    "subject": "alice",
    "object": "tenant-a/report",
    "action": "read",
    "rules": [
      {
        "subject": "alice",
        "object": "tenant-a/report",
        "action": "read",
        "effect": "allow"
      }
    ]
  },
  {
    "name": "conflict",
    "subject": "alice",
    "object": "tenant-a/report",
    "action": "read",
    "rules": [
      {
        "subject": "alice",
        "object": "tenant-a/report",
        "action": "read",
        "effect": "allow"
      },
      {
        "subject": "alice",
        "object": "tenant-a/report",
        "action": "read",
        "effect": "deny"
      }
    ]
  },
  {
    "name": "other-tenant",
    "subject": "alice",
    "object": "tenant-b/report",
    "action": "read",
    "rules": [
      {
        "subject": "alice",
        "object": "tenant-a/report",
        "action": "read",
        "effect": "allow"
      }
    ]
  }
]

读者自跑、成功和失败 ​

访问控制离线推演先复制三个文件到独立目录。Windows PowerShell使用python,Linux Bash使用python3调用lab.py case.json;命令在README完整列出。正常输入输出逐行判定并以0结束;缺字段、非法类型或JSON损坏输出invalid input并以2结束。预期拒绝是业务判定,不等同输入错误,仍以0结束。

恢复、清理与边界 ​

恢复时从仓库还原case.json,重新核对变更前后字段。程序不写结果文件,不产生系统资源,不需要关闭端口或停止服务。清理只删除读者自己复制的练习目录;不要删除仓库示例。修改输入不会改变真实授权、证书或路由。

综合练习与分开的解答 ​

练习:先不看参考答案,解释输入中每个正常和失败判定,修改一项条件让一个判定改变,再写出该变化仍不能证明的现实条件。

参考解答

read只命中alice对tenant-a/report的read允许,所以ALLOW。conflict同一三元组同时allow与deny,必须DENY_EXPLICIT,与列表顺序无关。other-tenant的资源不匹配,DENY_DEFAULT。输入缺字段则invalid input且退出2,与正常拒绝的退出0不同。

具体变体:只把 read 记录的 action 改为 write,保持规则只有read许可,将由 ALLOW 变为 DENY_DEFAULT。这是无匹配许可导致的缺省拒绝,不是命中显式deny;没有理由为让示例通过而给真实策略增加通配权限。

产品配置与操作契约 ​

以下为与离线模型分开的完整产品配置,示例未执行。产品二进制、真实密钥与账户均需读者按前置另行提供;静态解析不等于产品验证。

ini
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, eft

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
csv
p, alice, tenant-a/report, read, allow
p, alice, tenant-a/report, delete, allow
p, alice, tenant-a/report, delete, deny

完整Casbin策略配置(未执行) ​

model.conf与policy.csv是完整的精确主体/资源/动作、拒绝优先模型。r.sub来自可信认证;r.obj是含租户的规范化资源ID;r.act是应用固定动作。p.eft仅允许allow或deny,未知效应必须由策略发布层拒绝。没有g角色定义,没有超级用户旁路,没有通配符,避免读者把该模型误读成已实现RBAC。

效应表达式同时要求存在allow且不存在deny;单独使用deny-override而没有allow检查,可能使未匹配请求的语义不同,因此不可省略前半条件。policy.csv允许alice读取tenant-a/report;delete同时allow与deny,结果应为拒绝;tenant-b/report无匹配策略,也应拒绝。Python lab.py表达同一子集,但没有加载Casbin配置,不能拿它当Casbin兼容性测试。

配置阅读不需要第三方依赖。若读者另行集成真实Casbin,必须选定相应语言适配器/版本并用以上三例及未知主体检验;本包没有声明某个未安装SDK已通过。发布时先审阅策略文件,再由真实应用加载两个明确路径;失败保持旧批准策略或拒绝新请求,不回退到全放行。

清理仅删除练习副本或撤销另行批准的实验策略,不能撤销生产保护。此仓库不接入真实身份源,不执行Enforce。

完整项目说明与依赖声明 ​

以下同源文件完整列出读者前置、自跑命令、正常/失败预期和清理;正文只供阅读,示例未执行。

text
# Python >=3.11; standard library only; no third-party dependencies.
完整 README(与项目文件一致)
markdown
# security 离线证据推演

示例未执行。lab.py 演示主体、租户资源和动作的精确匹配,以及显式拒绝优先于允许;它不认证用户,也不加载后半节的 Casbin 配置。先确定主体来自何处、资源如何包含租户,再判断一次请求是否获准。

## 文件与前置

离线部分需要 Python 3.11 以上和标准库,无 Casbin SDK、服务或管理员权限。从 [case.json](case.json) 的允许、允许/拒绝冲突与跨租户三例入手,对照 [lab.py](lab.py) 的精确三元组匹配。model.conf/policy.csv 是后半节另行说明的配置,不是本程序的运行输入;macOS 未做原生运行验收。

## 读者自跑

先复制全部文件到自己的隔离练习目录并进入该目录。以下仅是读者步骤,本轮未执行。

Windows PowerShell:

```powershell
python .\lab.py .\case.json
```

Linux Bash(macOS若已有Python3也使用此形式):

```bash
python3 ./lab.py ./case.json
```

预期标准输出如下,进程退出0;明确拒绝是正常决策而不是输入错误。

```text
read: ALLOW
conflict: DENY_EXPLICIT
other-tenant: DENY_DEFAULT
```

## 失败路径

把case.json复制为broken.json,再人工删除第一条记录的name字段。使用同一命令把参数换成broken.json,预期标准错误invalid input、退出2,不发布部分判定。破损JSON、非法字段类型、未知字段、空列表或不存在的文件同样退出2。不打印异常原文,防止输入内容意外进入日志。程序严格匹配固定教学字段,不接受任意扩展。

## 恢复与清理

从原仓库重新复制case.json恢复,或撤销练习副本编辑。程序没有写文件、创建用户或启动连接,无需服务清理;只删除自己复制的目录和broken.json,不删除仓库原文件。

## 解释边界

这是精确三元组、拒绝优先的教学决策器,不是Casbin实现,没有角色、通配符或认证。subject须在真实系统中来自可信认证;不能用于生产权限保护。

输入由读者提供,不具有独立真实性。需要真实运行验证时,另行取得授权并采集环境证据,不能用本程序作产品验收工具。

## 完整Casbin策略配置(未执行)

model.conf与policy.csv是完整的精确主体/资源/动作、拒绝优先模型。r.sub来自可信认证;r.obj是含租户的规范化资源ID;r.act是应用固定动作。p.eft仅允许allow或deny,未知效应必须由策略发布层拒绝。没有g角色定义,没有超级用户旁路,没有通配符,避免读者把该模型误读成已实现RBAC。

效应表达式同时要求存在allow且不存在deny;单独使用deny-override而没有allow检查,可能使未匹配请求的语义不同,因此不可省略前半条件。policy.csv允许alice读取tenant-a/report;delete同时allow与deny,结果应为拒绝;tenant-b/report无匹配策略,也应拒绝。Python lab.py表达同一子集,但没有加载Casbin配置,不能拿它当Casbin兼容性测试。

配置阅读不需要第三方依赖。若读者另行集成真实Casbin,必须选定相应语言适配器/版本并用以上三例及未知主体检验;本包没有声明某个未安装SDK已通过。发布时先审阅策略文件,再由真实应用加载两个明确路径;失败保持旧批准策略或拒绝新请求,不回退到全放行。

清理仅删除练习副本或撤销另行批准的实验策略,不能撤销生产保护。此仓库不接入真实身份源,不执行Enforce。

继续阅读