2个不稳定版本
0.9.0-rc.1 | 2023年7月6日 |
---|---|
0.7.0-dev.1 |
|
0.6.0-dev.1 |
|
#472 in 异步
99 每月下载量
78KB
1.5K SLoC
警告 ⚠️ ️: 此项目处于积极开发中
minos
Minos授权语言的授权库。此仓库包含语言定义、解析器和授权引擎。
Minos授权
...
Minos语言
Minos语言是一种领域特定语言,专为编写授权策略而创建。
要描述语法,我们首先从下一个文件开始
/* in example.minos */
syntax = 0.16;
/* Resource declaration */
resource User {
/* Environment declaration */
env DEFAULT {
/* policy declaration */
policy {
/* Permissions granted if at least one rule is met */
allow = ["create", "read", "update", "delete"];
/* Rule declaration */
rule {
actor.type = RootUser;
}
rule {
actor.type = resource.type;
actor.id = resource.id;
}
}
}
}
首先,Minos文件中的注释写在与CSS相同的字符 /*
和 */
之间。
/*in example.minos */
每个Minos文件需要在文档开头声明所使用的语法版本。
syntax = 0.16;
...
现在,我们可以回到整个文件
syntax = 0.16;
resource User {
env DEFAULT {
policy {
allow = ["create", "read", "update", "delete"];
rule {
actor.type = RootUser;
}
rule {
actor.type = resource.type;
actor.id = resource.id;
}
}
}
}
此块描述了一个名为 User
的资源,仅有一个名为 DEFAULT
的环境。重要的是要指出,如果存在 DEFAULT
块,它将在每个授权过程中应用。
隐式环境
基于以上内容,我们可以重写此块,不使用环境
resource User {
policy {
allow = ["create", "read", "update", "delete"];
rule {
actor.type = RootUser;
}
rule {
actor.type = resource.type;
actor.id = resource.id;
}
}
}
代码将被解析为前面的示例,但在此情况下,DEFAULT
块是隐式的。此功能称为“隐式默认”。
命名环境
环境为策略提供封装。为了排除“默认行为”模式,可以使用命名环境。我们可以修改示例,并定义两个环境: Testing
和 Production
。
resource User {
env Testing {
policy {
allow = ["create", "read", "update", "delete"];
rule {
actor.type = RootUser;
}
rule {
actor.type = resource.type;
actor.id = resource.id;
}
}
}
env Production {
policy {
allow = ["create", "read", "update", "delete"];
rule {
actor.type = resource.type;
actor.id = resource.id;
}
}
}
}
我们可以看到,在 Testing
环境中, RootUser
可以操作 Users
,但在 Production
中,只有 User
可以操作自己。
需要注意的是,当存在两个或多个环境时,无法使用隐式 DEFAULT
。因为在这种情况下,DEFAULT
块不存在,并且在授权过程中需要指示环境名称。
现在,如果我们确定只需要两个环境,我们可以使用 DEFAULT
环境重写代码。
resource User {
env DEFAULT {
policy {
allow = ["create", "read", "update", "delete"];
rule {
actor.type = resource.type;
actor.id = resource.id;
}
}
}
env Testing {
policy {
allow = ["create", "read", "update", "delete"];
rule {
actor.type = RootUser;
}
}
}
}
这种模式清楚地表明这是一个边缘情况,并允许我们在部署前移除Testing
环境。但是,我们之所以这样做,仅仅是因为规则是兼容的,并且我们想要使用DEFAULT
环境。
规范
如果我们需要根据资源本身而不是环境实现不同的行为呢?这可以通过使用规范功能和属性资源来实现。
以下示例中,我们可以定义两个不同的块
resource File {
policy {
allow = ["read"];
rule {
actor.type = User;
}
}
policy {
allow = ["write", "delete"];
rule {
actor.roles *= ["admin"];
}
}
}
resource File {
id = "confidential.john.data.file.id";
policy {
allow = ["read"];
rule {
actor.id = "john.user.Id";
}
}
}
第一个块定义了一个名为File
的资源。根据规则,用户可以读取File
,但只有具有“admin”角色的actor才能写入或删除File
。
在第二个块中,我们发现对File
的另一个声明。我们可以看到一些不同之处
- 资源有一个名为
id
的属性,因此这是一个属性资源; - 资源有一个包含冲突性规则的策略,因为在同一环境中,对“读取”权限的授权使用了两个策略。
在这种情况下,授权过程是如何工作的?如果资源是File
并且其id是"confidential.john.data.file.id",则忽略File
的规则,而只应用匹配id的策略。结果是,具有id "confidential.john.data.file.id"的File
不能被覆盖或删除。
很简单,如果我们想为特定资源定义特殊规则,我们只需使用规范。
规则中使用id属性
但是,如果我们想将规则用于DEFAULT
环境而不是忽略它,我们可以像这样扩展第一个块
resource File {
policy {
allow = ["read"];
rule {
actor.type = User;
}
/* start of adition --- */
rule {
resource.id = "confidential.john.data.file.id";
actor.id = "john.user.Id";
}
/* --- end of adition */
}
policy {
allow = ["write", "delete"];
rule {
actor.roles *= ["admin"];
}
}
}
上面的代码将被解析,因为具有id "john.user.Id"的actor可以读取具有id "confidential.john.data.file.id"的File
。我们可以看到,如果actor是User
,则新规则实际上是无用的。这是使用actor.id
和/或resource.id
在同一环境中的问题:严格规则可能会被更宽松的规则跳过。
属性比较
在最后一个示例中,使用id属性的情况仅适用于actor不是User
的情况。因此,我们可以使用上述代码处理以下数据
{
"actor": {
"id": "john.user.Id",
"type": "Employee",
"groups": ["employees"],
"roles": ["admin"]
},
"resource": {
"id": "confidential.john.data.file.id",
"type": "File",
"owner": "john.user.Id"
},
"permissions": ["read"]
}
授权已授予,因为规则正好涵盖了这种情况。那么,如果我们为每位员工都有一个机密文件怎么办?我们必须为每个文件-员工对编写一个规则吗?不一定,我们可以使用actor.owner
属性,这在当前minos语言版本(v0.16)中已经得到了很好的支持。
resource File {
policy {
allow = ["read"];
rule {
actor.type = User;
}
/* start of change --- */
rule {
resource.owner = actor.id;
}
/* --- end of change */
}
policy {
allow = ["write", "delete"];
rule {
actor.roles *= ["admin"];
}
}
}
此外,还可以通过添加actor.type
要求来增强规则
/*... */
rule {
actor.type = Employee;
resource.owner = actor.id;
}
/*...*/
属性比较是避免常见逻辑重复的好方法。不幸的是,在当前minos语言版本(v0.16)中,支持的属性并不多。但我们希望在未来版本中改进对该功能的支持。
解析规则
在此阶段,重要的是解释minos解析器如何处理具有相同标识符的块。例如,[本节](#Use of id attribute in rules)的代码可以重写如下
resource File {
policy {
allow = ["read"];
rule {
actor.type = User;
}
rule {
resource.id = "confidential.john.data.file.id";
actor.id = "john.user.Id";
}
}
}
resource File {
policy {
allow = ["write", "delete"];
rule {
actor.roles *= ["admin"];
}
}
}
minos是如何解析上述文本的?
- 搜索资源。
- 添加
File
资源。 - 搜索环境。
- 添加隐式
DEFAULT
环境。 - 搜索策略。
- 添加策略以允许权限
["read"]
和两条规则。 - 搜索更多策略。
- 跳过搜索更多环境,因为该块使用隐式
DEFAULT
。 - 搜索更多资源。
- 找到
文件
资源。 - 搜索环境。
- 找到隐式 DEFAULT 环境。
- 搜索策略。
- 添加策略以允许权限
["write", "delete"]
和一条规则。 - 搜索更多策略。
- 跳过搜索更多环境,因为该块使用隐式
DEFAULT
。 - 搜索更多资源 ...
此行为与其他文件中的资源相同。例如,我们可以将上面的代码重写如下
/* in file.minos */
resource File {
policy {
allow = ["read"];
rule {
actor.type = User;
}
}
}
/* in file2.minos */
resource File {
policy {
allow = ["read"];
rule {
resource.id = "confidential.john.data.file.id";
actor.id = "john.user.Id";
}
}
}
/* in file3.minos */
resource File {
policy {
allow = ["write", "delete"];
rule {
actor.roles *= ["admin"];
}
}
}
最终的解析,将与此节第一个示例完全相同。
依赖项
~7MB
~132K SLoC