feat: add pattern model
Signed-off-by: Zixuan Liu <nodeces@gmail.com>
This commit is contained in:
parent
3fb1f91e6e
commit
207a5a23c2
|
@ -22,4 +22,3 @@ dist
|
|||
build
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"keywords": [],
|
||||
"main": "src/index.js",
|
||||
"dependencies": {
|
||||
"casbin": "^5.0.5",
|
||||
"casbin": "^5.1.6",
|
||||
"codemirror": "5.48.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "16.12.0",
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
/* eslint-disable */
|
||||
|
||||
const exampleModel = {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.sub == p.sub && r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic_with_root:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic_without_resources:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.sub == p.sub && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic_without_users:
|
||||
'[request_definition]\n' +
|
||||
'r = obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[role_definition]\n' +
|
||||
'g = _, _\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac_with_resource_roles:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[role_definition]\n' +
|
||||
'g = _, _\n' +
|
||||
'g2 = _, _\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac_with_domains:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, dom, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, dom, obj, act\n' +
|
||||
'\n' +
|
||||
'[role_definition]\n' +
|
||||
'g = _, _, _\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac_with_deny:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act, eft\n' +
|
||||
'\n' +
|
||||
'[role_definition]\n' +
|
||||
'g = _, _\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow)) && !some(where (p.eft == deny))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
abac:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.sub == r.obj.Owner',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
abac_with_policy_rule:
|
||||
'[request_definition]\n'+
|
||||
'r = sub, obj, act\n'+
|
||||
'\n'+
|
||||
'[policy_definition]\n'+
|
||||
'p = sub_rule, obj, act\n'+
|
||||
'\n'+
|
||||
'[policy_effect]\n'+
|
||||
'e = some(where (p.eft == allow))\n'+
|
||||
'\n'+
|
||||
'[matchers]\n'+
|
||||
'm = eval(p.sub_rule) && r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
keymatch:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
keymatch2:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = r.sub == p.sub && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
ipmatch:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = some(where (p.eft == allow))\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = ipMatch(r.sub, p.sub) && r.obj == p.obj && r.act == p.act',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
priority:
|
||||
'[request_definition]\n' +
|
||||
'r = sub, obj, act\n' +
|
||||
'\n' +
|
||||
'[policy_definition]\n' +
|
||||
'p = sub, obj, act, eft\n' +
|
||||
'\n' +
|
||||
'[role_definition]\n' +
|
||||
'g = _, _\n' +
|
||||
'\n' +
|
||||
'[policy_effect]\n' +
|
||||
'e = priority(p.eft) || deny\n' +
|
||||
'\n' +
|
||||
'[matchers]\n' +
|
||||
'm = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act'
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
export default exampleModel;
|
|
@ -1,81 +0,0 @@
|
|||
/* eslint-disable */
|
||||
|
||||
const examplePolicy = {
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic: 'p, alice, data1, read\n' + 'p, bob, data2, write',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic_with_root: 'p, alice, data1, read\n' + 'p, bob, data2, write',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic_without_resources: 'p, alice, read\n' + 'p, bob, write',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
basic_without_users: 'p, data1, read\n' + 'p, data2, write',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac:
|
||||
'p, alice, data1, read\n' +
|
||||
'p, bob, data2, write\n' +
|
||||
'p, data2_admin, data2, read\n' +
|
||||
'p, data2_admin, data2, write\n' +
|
||||
'\n' +
|
||||
'g, alice, data2_admin',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac_with_resource_roles:
|
||||
'p, alice, data1, read\n' +
|
||||
'p, bob, data2, write\n' +
|
||||
'p, data_group_admin, data_group, write\n' +
|
||||
'\n' +
|
||||
'g, alice, data_group_admin\n' +
|
||||
'g2, data1, data_group\n' +
|
||||
'g2, data2, data_group',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac_with_domains:
|
||||
'p, admin, domain1, data1, read\n' +
|
||||
'p, admin, domain1, data1, write\n' +
|
||||
'p, admin, domain2, data2, read\n' +
|
||||
'p, admin, domain2, data2, write\n' +
|
||||
'\n' +
|
||||
'g, alice, admin, domain1\n' +
|
||||
'g, bob, admin, domain2',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
rbac_with_deny:
|
||||
'p, alice, data1, read, allow\n' +
|
||||
'p, bob, data2, write, allow\n' +
|
||||
'p, data2_admin, data2, read, allow\n' +
|
||||
'p, data2_admin, data2, write, allow\n' +
|
||||
'p, alice, data2, write, deny\n' +
|
||||
'\n' +
|
||||
'g, alice, data2_admin',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
abac: '',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
abac_with_policy_rule: 'p, r.sub.Age > 18 && r.sub.Age < 60, /data1, read\n',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
keymatch:
|
||||
'p, alice, /alice_data/*, GET\n' +
|
||||
'p, alice, /alice_data/resource1, POST\n' +
|
||||
'\n' +
|
||||
'p, bob, /alice_data/resource2, GET\n' +
|
||||
'p, bob, /bob_data/*, POST\n' +
|
||||
'\n' +
|
||||
'p, cathy, /cathy_data, (GET)|(POST)',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
keymatch2: 'p, alice, /alice_data/:resource, GET\n' + 'p, alice, /alice_data2/:id/using/:resId, GET',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
ipmatch: 'p, 192.168.2.0/24, data1, read\n' + 'p, 10.0.0.0/16, data2, write',
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
priority:
|
||||
'p, alice, data1, read, allow\n' +
|
||||
'p, data1_deny_group, data1, read, deny\n' +
|
||||
'p, data1_deny_group, data1, write, deny\n' +
|
||||
'p, alice, data1, write, allow\n' +
|
||||
'\n' +
|
||||
'g, alice, data1_deny_group\n' +
|
||||
'\n' +
|
||||
'p, data2_allow_group, data2, read, allow\n' +
|
||||
'p, bob, data2, read, deny\n' +
|
||||
'p, bob, data2, write, deny\n' +
|
||||
'\n' +
|
||||
'g, bob, data2_allow_group'
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
export default examplePolicy;
|
|
@ -1,19 +0,0 @@
|
|||
/* eslint-disable */
|
||||
const exampleRequest = {
|
||||
basic: 'alice, data1, read',
|
||||
basic_with_root: 'alice, data1, read',
|
||||
basic_without_resources: 'alice, read',
|
||||
basic_without_users: 'data1, read',
|
||||
rbac: 'alice, data2, read',
|
||||
rbac_with_resource_roles: 'alice, data1, read\n' + 'alice, data1, write\n' + 'alice, data2, read\n' + 'alice, data2, write ',
|
||||
rbac_with_domains: 'alice, domain1, data1, read',
|
||||
rbac_with_deny: 'alice, data1, read\n' + 'alice, data2, write',
|
||||
abac: `alice, { Owner: 'alice'}\n` + `alice, { Owner: 'bob'}`,
|
||||
abac_with_policy_rule: `{ Age: 30}, /data1, read`,
|
||||
keymatch: 'alice, /alice_data/hello, GET',
|
||||
keymatch2: 'alice, /alice_data/hello, GET\n' + 'alice, /alice_data/hello, POST',
|
||||
ipmatch: '192.168.2.1, data1, read\n' + '10.0.2.3, data2, write',
|
||||
priority: 'alice, data1, read'
|
||||
};
|
||||
|
||||
export default exampleRequest;
|
|
@ -0,0 +1,414 @@
|
|||
export const example = {
|
||||
basic: {
|
||||
name: 'ACL',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, alice, data1, read
|
||||
p, bob, data2, write`,
|
||||
request: `alice, data1, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
basic_with_root: {
|
||||
name: 'ACL with superuser',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"`,
|
||||
policy: `p, alice, data1, read
|
||||
p, bob, data2, write`,
|
||||
request: `alice, data1, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
basic_without_resources: {
|
||||
name: 'ACL without resources',
|
||||
model: `[request_definition]
|
||||
r = sub, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.act == p.act`,
|
||||
policy: `p, alice, read
|
||||
p, bob, write`,
|
||||
request: `alice, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
basic_without_users: {
|
||||
name: 'ACL without users',
|
||||
model: `[request_definition]
|
||||
r = obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, data1, read
|
||||
p, data2, write`,
|
||||
request: `data1, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
rbac: {
|
||||
name: 'RBAC',
|
||||
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) && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, alice, data1, read
|
||||
p, bob, data2, write
|
||||
p, data2_admin, data2, read
|
||||
p, data2_admin, data2, write
|
||||
|
||||
g, alice, data2_admin`,
|
||||
request: `alice, data2, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
rbac_with_resource_roles: {
|
||||
name: 'RBAC with resource roles',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[role_definition]
|
||||
g = _, _
|
||||
g2 = _, _
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act`,
|
||||
policy: `p, alice, data1, read
|
||||
p, bob, data2, write
|
||||
p, data_group_admin, data_group, write
|
||||
|
||||
g, alice, data_group_admin
|
||||
g2, data1, data_group
|
||||
g2, data2, data_group`,
|
||||
request: `alice, data1, read
|
||||
alice, data1, write
|
||||
alice, data2, read
|
||||
alice, data2, write `,
|
||||
|
||||
customConfig: undefined
|
||||
},
|
||||
rbac_with_domains: {
|
||||
name: 'RBAC with domains/tenants',
|
||||
model: `[request_definition]
|
||||
r = sub, dom, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, dom, obj, act
|
||||
|
||||
[role_definition]
|
||||
g = _, _, _
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, admin, domain1, data1, read
|
||||
p, admin, domain1, data1, write
|
||||
p, admin, domain2, data2, read
|
||||
p, admin, domain2, data2, write
|
||||
|
||||
g, alice, admin, domain1
|
||||
g, bob, admin, domain2`,
|
||||
request: `alice, domain1, data1, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
rbac_with_pattern: {
|
||||
name: 'RBAC with pattern',
|
||||
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) && regexMatch(r.act, p.act)`,
|
||||
policy: `
|
||||
p, pen_admin, data1, GET
|
||||
|
||||
g, /book/:id, book_admin
|
||||
`,
|
||||
request: `/book/1, data1, GET`,
|
||||
customConfig: `
|
||||
(function() {
|
||||
return {
|
||||
/**
|
||||
* Here is custom functions for Casbin.
|
||||
* Currently, there are built-in globMatch, keyMatch, keyMatch2, keyMatch3, keyMatch4, regexMatch, ipMatch.
|
||||
*/
|
||||
functions: {},
|
||||
/**
|
||||
* The value comes from config.functions, Casbin will not use this configuration if the value is undefined.
|
||||
* example:
|
||||
* matchingForGFunction: 'globMatch'
|
||||
* matchingDomainForGFunction: 'keyMatch'
|
||||
*/
|
||||
matchingForGFunction: 'keyMatch2',
|
||||
matchingDomainForGFunction: undefined
|
||||
};
|
||||
})();`
|
||||
},
|
||||
rbac_with_all_pattern: {
|
||||
name: 'RBAC with all pattern',
|
||||
model: `[request_definition]
|
||||
r = sub, dom, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, dom, obj, act
|
||||
|
||||
[role_definition]
|
||||
g = _, _, _
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, book_group, domain1, data1, read
|
||||
p, book_group, domain2, data2, write
|
||||
|
||||
g, /book/:id, book_group, *`,
|
||||
request: `/book/1, domain1, data1, read
|
||||
/book/1, domain2, data2, write
|
||||
`,
|
||||
customConfig: `
|
||||
(function() {
|
||||
return {
|
||||
/**
|
||||
* Here is custom functions for Casbin.
|
||||
* Currently, there are built-in globMatch, keyMatch, keyMatch2, keyMatch3, keyMatch4, regexMatch, ipMatch.
|
||||
*/
|
||||
functions: {},
|
||||
/**
|
||||
* The value comes from config.functions, Casbin will not use this configuration if the value is undefined.
|
||||
* example:
|
||||
* matchingForGFunction: 'globMatch'
|
||||
* matchingDomainForGFunction: 'keyMatch'
|
||||
*/
|
||||
matchingForGFunction: 'keyMatch2',
|
||||
matchingDomainForGFunction: 'keyMatch2'
|
||||
};
|
||||
})();`
|
||||
},
|
||||
rbac_with_deny: {
|
||||
name: 'RBAC with deny-override',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act, eft
|
||||
|
||||
[role_definition]
|
||||
g = _, _
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
|
||||
|
||||
[matchers]
|
||||
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, alice, data1, read, allow
|
||||
p, bob, data2, write, allow
|
||||
p, data2_admin, data2, read, allow
|
||||
p, data2_admin, data2, write, allow
|
||||
p, alice, data2, write, deny
|
||||
|
||||
g, alice, data2_admin`,
|
||||
request: `alice, data1, read
|
||||
alice, data2, write`,
|
||||
customConfig: undefined
|
||||
},
|
||||
abac: {
|
||||
name: 'ABAC',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == r.obj.Owner`,
|
||||
policy: '',
|
||||
request: `alice, { Owner: 'alice'}
|
||||
alice, { Owner: 'bob'}`,
|
||||
customConfig: undefined
|
||||
},
|
||||
abac_with_policy_rule: {
|
||||
name: 'ABAC with policy rule',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub_rule, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = eval(p.sub_rule) && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, r.sub.Age > 18 && r.sub.Age < 60, /data1, read
|
||||
`,
|
||||
request: `{ Age: 30}, /data1, read`,
|
||||
customConfig: undefined
|
||||
},
|
||||
keymatch: {
|
||||
name: 'RESTful (KeyMatch)',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)`,
|
||||
policy: `p, alice, /alice_data/*, GET
|
||||
p, alice, /alice_data/resource1, POST
|
||||
|
||||
p, bob, /alice_data/resource2, GET
|
||||
p, bob, /bob_data/*, POST
|
||||
|
||||
p, cathy, /cathy_data, (GET)|(POST)`,
|
||||
request: 'alice, /alice_data/hello, GET',
|
||||
customConfig: undefined
|
||||
},
|
||||
keymatch2: {
|
||||
name: 'RESTful (KeyMatch2)',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)`,
|
||||
policy: `p, alice, /alice_data/:resource, GET
|
||||
p, alice, /alice_data2/:id/using/:resId, GET`,
|
||||
request: `alice, /alice_data/hello, GET
|
||||
alice, /alice_data/hello, POST`,
|
||||
customConfig: undefined
|
||||
},
|
||||
ipmatch: {
|
||||
name: 'IP match',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = ipMatch(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, 192.168.2.0/24, data1, read
|
||||
p, 10.0.0.0/16, data2, write`,
|
||||
request: `192.168.2.1, data1, read
|
||||
10.0.2.3, data2, write`,
|
||||
customConfig: undefined
|
||||
},
|
||||
priority: {
|
||||
name: 'Priority',
|
||||
model: `[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = sub, obj, act, eft
|
||||
|
||||
[role_definition]
|
||||
g = _, _
|
||||
|
||||
[policy_effect]
|
||||
e = priority(p.eft) || deny
|
||||
|
||||
[matchers]
|
||||
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`,
|
||||
policy: `p, alice, data1, read, allow
|
||||
p, data1_deny_group, data1, read, deny
|
||||
p, data1_deny_group, data1, write, deny
|
||||
p, alice, data1, write, allow
|
||||
|
||||
g, alice, data1_deny_group
|
||||
|
||||
p, data2_allow_group, data2, read, allow
|
||||
p, bob, data2, read, deny
|
||||
p, bob, data2, write, deny
|
||||
|
||||
g, bob, data2_allow_group`,
|
||||
request: `alice, data1, read`,
|
||||
customConfig: undefined
|
||||
}
|
||||
};
|
||||
|
||||
export const defaultCustomConfig = `(function() {
|
||||
return {
|
||||
/**
|
||||
* Here is custom functions for Casbin.
|
||||
* Currently, there are built-in globMatch, keyMatch, keyMatch2, keyMatch3, keyMatch4, regexMatch, ipMatch.
|
||||
*/
|
||||
functions: {},
|
||||
/**
|
||||
* The value comes from config.functions, Casbin will not use this configuration if the value is undefined.
|
||||
* example:
|
||||
* matchingForGFunction: 'globMatch'
|
||||
* matchingDomainForGFunction: 'keyMatch'
|
||||
*/
|
||||
matchingForGFunction: undefined,
|
||||
matchingDomainForGFunction: undefined
|
||||
};
|
||||
})();`
|
||||
export type Example = typeof example;
|
||||
export type ModelKind = keyof Example;
|
|
@ -11,9 +11,10 @@ import 'codemirror/addon/edit/matchbrackets';
|
|||
import 'codemirror/addon/display/placeholder';
|
||||
import './casbin-mode/casbin-conf';
|
||||
import './casbin-mode/casbin-csv';
|
||||
import { ModelKind } from './casbin-mode/example';
|
||||
|
||||
interface CasbinCodeMirror {
|
||||
modelKind: string;
|
||||
modelKind: ModelKind;
|
||||
options: codemirror.EditorConfiguration;
|
||||
style?: CSSProperties;
|
||||
onChange: (text: string) => void;
|
||||
|
@ -21,7 +22,7 @@ interface CasbinCodeMirror {
|
|||
}
|
||||
|
||||
interface EditorProps {
|
||||
modelKind: string;
|
||||
modelKind: ModelKind;
|
||||
onChange?: (text: string) => void;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
import React, { isValidElement, useState } from 'react';
|
||||
import React, { isValidElement, useEffect, useState } from 'react';
|
||||
import SelectModel from './select-model';
|
||||
import { Button, EditorContainer, FlexRow, HeaderTitle } from '../ui';
|
||||
import { getSelectedModel, reset } from './persist';
|
||||
import { CustomFunctionEditor, ModelEditor, PolicyEditor, RequestEditor, RequestResultEditor } from './editor';
|
||||
import Syntax from './syntax';
|
||||
import RunTest from './run-test';
|
||||
import { ModelKind } from './casbin-mode/example';
|
||||
|
||||
export const EditorScreen = () => {
|
||||
const [modelKind, setModelKind] = useState(getSelectedModel());
|
||||
const [modelKind, setModelKind] = useState<ModelKind>(getSelectedModel());
|
||||
const [modelText, setModelText] = useState('');
|
||||
const [policy, setPolicy] = useState('');
|
||||
const [fn, setFn] = useState('');
|
||||
const [customConfig, setCustomConfig] = useState('');
|
||||
const [request, setRequest] = useState('');
|
||||
const [echo, setEcho] = useState<JSX.Element>(<></>);
|
||||
const [requestResult, setRequestResult] = useState('');
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [customConfigVisible, setCustomConfigVisible] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// Automatically hide the custom config container.
|
||||
setTimeout(() => {
|
||||
setCustomConfigVisible(false);
|
||||
}, 2000);
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<FlexRow>
|
||||
|
@ -24,7 +31,7 @@ export const EditorScreen = () => {
|
|||
<HeaderTitle>Model</HeaderTitle>
|
||||
<SelectModel
|
||||
onChange={value => {
|
||||
setModelKind(value);
|
||||
setModelKind(value as ModelKind);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
|
@ -62,10 +69,10 @@ export const EditorScreen = () => {
|
|||
<FlexRow>
|
||||
<EditorContainer>
|
||||
<FlexRow>
|
||||
<HeaderTitle>Custom Function</HeaderTitle>
|
||||
<Button onClick={() => setVisible(!visible)}>TOGGLE</Button>
|
||||
<HeaderTitle>Custom Config</HeaderTitle>
|
||||
<Button onClick={() => setCustomConfigVisible(!customConfigVisible)}>TOGGLE</Button>
|
||||
</FlexRow>
|
||||
{visible && <CustomFunctionEditor modelKind={modelKind} onChange={setFn} />}
|
||||
{customConfigVisible && <CustomFunctionEditor modelKind={modelKind} onChange={setCustomConfig} />}
|
||||
</EditorContainer>
|
||||
</FlexRow>
|
||||
|
||||
|
@ -75,7 +82,7 @@ export const EditorScreen = () => {
|
|||
modelKind={modelKind}
|
||||
model={modelText}
|
||||
policy={policy}
|
||||
fn={fn}
|
||||
customConfig={customConfig}
|
||||
request={request}
|
||||
onResponse={v => {
|
||||
if (isValidElement(v)) {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import exampleModel from './casbin-mode/example-model';
|
||||
import examplePolicy from './casbin-mode/example-policy';
|
||||
import exampleRequest from './casbin-mode/example-request';
|
||||
import { defaultCustomConfig, example, ModelKind } from './casbin-mode/example';
|
||||
|
||||
export const DEFAULT_MODEL = 'basic';
|
||||
export const DEFAULT_MODEL: ModelKind = 'basic';
|
||||
|
||||
export enum Persist {
|
||||
MODEL,
|
||||
|
@ -15,30 +13,32 @@ function getKey(persist: Persist, modelName: string) {
|
|||
return `${modelName.toUpperCase()}_${Persist[persist]}`;
|
||||
}
|
||||
|
||||
export function getSelectedModel() {
|
||||
const v = window.localStorage.getItem(Persist.MODEL.toString());
|
||||
return v ? v : DEFAULT_MODEL;
|
||||
export function getSelectedModel(): ModelKind {
|
||||
const v = window.localStorage.getItem(Persist[Persist.MODEL].toString());
|
||||
return (v ? v : DEFAULT_MODEL) as ModelKind;
|
||||
}
|
||||
|
||||
export function setSelectedModel(value: string) {
|
||||
window.localStorage.setItem(Persist[Persist.MODEL], value);
|
||||
}
|
||||
|
||||
export function get(persist: Persist, modelName = DEFAULT_MODEL) {
|
||||
export function get(persist: Persist, modelName: ModelKind = DEFAULT_MODEL) {
|
||||
const data = window.localStorage.getItem(getKey(persist, modelName));
|
||||
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const m = example[modelName];
|
||||
switch (persist) {
|
||||
case Persist.MODEL:
|
||||
return (exampleModel as any)[modelName];
|
||||
return m.model;
|
||||
case Persist.POLICY:
|
||||
return (examplePolicy as any)[modelName];
|
||||
return m.policy;
|
||||
case Persist.REQUEST:
|
||||
return (exampleRequest as any)[modelName];
|
||||
return m.request;
|
||||
case Persist.CUSTOM_FUNCTION:
|
||||
return `var fns = {}`;
|
||||
return m.customConfig || defaultCustomConfig;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import React from 'react';
|
||||
import { Button, Echo } from '../ui';
|
||||
import { newEnforcer, newModel, StringAdapter } from 'casbin';
|
||||
import { DefaultRoleManager, newEnforcer, newModel, StringAdapter, Util } from 'casbin';
|
||||
|
||||
interface RunTestProps {
|
||||
model: string;
|
||||
modelKind: string;
|
||||
policy: string;
|
||||
fn: string;
|
||||
customConfig: string;
|
||||
request: string;
|
||||
onResponse: (com: JSX.Element | any[]) => void;
|
||||
}
|
||||
|
||||
const needsAbacParsing = new Set(['abac','abac_with_policy_rule']);
|
||||
const needsAbacParsing = new Set(['abac', 'abac_with_policy_rule']);
|
||||
|
||||
function parseABACRequest(line: string): any[] {
|
||||
let value = '';
|
||||
|
@ -27,7 +27,7 @@ function parseABACRequest(line: string): any[] {
|
|||
if (objectToken === 0 && line[i] === ',') {
|
||||
if (parseToObject) {
|
||||
// eslint-disable-next-line
|
||||
eval(`value = ${value}`);
|
||||
value = eval(`(${value})`);
|
||||
}
|
||||
request.push(value);
|
||||
|
||||
|
@ -56,7 +56,7 @@ function parseABACRequest(line: string): any[] {
|
|||
if (value) {
|
||||
if (parseToObject) {
|
||||
// eslint-disable-next-line
|
||||
eval(`value = ${value}`);
|
||||
value = eval(`(${value})`);
|
||||
}
|
||||
request.push(value);
|
||||
}
|
||||
|
@ -64,59 +64,105 @@ function parseABACRequest(line: string): any[] {
|
|||
return request;
|
||||
}
|
||||
|
||||
async function enforcer(props: RunTestProps) {
|
||||
debugger;
|
||||
const startTime = performance.now();
|
||||
const result = [];
|
||||
try {
|
||||
const e = await newEnforcer(newModel(props.model), props.policy ? new StringAdapter(props.policy) : undefined);
|
||||
|
||||
const customConfigCode = props.customConfig;
|
||||
if (customConfigCode) {
|
||||
try {
|
||||
const builtinFunc = {
|
||||
keyMatch: Util.keyMatchFunc,
|
||||
keyMatch2: Util.keyMatch2Func,
|
||||
keyMatch3: Util.keyMatch3Func,
|
||||
keyMatch4: Util.keyMatch4Func,
|
||||
regexMatch: Util.regexMatchFunc,
|
||||
ipMatch: Util.ipMatchFunc,
|
||||
globMatch: Util.globMatch
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
let config = eval(customConfigCode);
|
||||
if (config) {
|
||||
config = { ...config, functions: { ...config.functions, ...builtinFunc } };
|
||||
if (config?.functions) {
|
||||
Object.keys(config.functions).forEach(key => e.addFunction(key, config.functions[key]));
|
||||
}
|
||||
|
||||
const rm = e.getRoleManager() as DefaultRoleManager;
|
||||
const matchingForGFunction = config.matchingForGFunction;
|
||||
if (matchingForGFunction) {
|
||||
if (typeof matchingForGFunction === 'function') {
|
||||
await rm.addMatchingFunc(matchingForGFunction);
|
||||
}
|
||||
if (typeof matchingForGFunction === 'string') {
|
||||
if (matchingForGFunction in config.functions) {
|
||||
console.warn('add matchingForGFunction');
|
||||
await rm.addMatchingFunc(config.functions[matchingForGFunction]);
|
||||
} else {
|
||||
props.onResponse(<Echo type={'error'}>Must sure the {matchingForGFunction}() in config.functions</Echo>);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const matchingDomainForGFunction = config.matchingDomainForGFunction;
|
||||
if (matchingDomainForGFunction) {
|
||||
if (typeof matchingDomainForGFunction === 'function') {
|
||||
console.warn('add addDomainMatchingFunc');
|
||||
await rm.addDomainMatchingFunc(matchingDomainForGFunction);
|
||||
}
|
||||
if (typeof matchingDomainForGFunction === 'string') {
|
||||
if (matchingDomainForGFunction in config.functions) {
|
||||
console.warn('add addDomainMatchingFunc');
|
||||
await rm.addDomainMatchingFunc(config.functions[matchingDomainForGFunction]);
|
||||
} else {
|
||||
props.onResponse(<Echo type={'error'}>Must sure the {matchingDomainForGFunction}() in config.functions</Echo>);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
props.onResponse(<Echo type={'error'}>Please check syntax in Custom Function Editor: {e.message}</Echo>);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const requests = props.request.split('\n');
|
||||
|
||||
for (const n of requests) {
|
||||
const line = n.trim();
|
||||
if (!line) {
|
||||
result.push('// ignore');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] === '#') {
|
||||
result.push('// ignore');
|
||||
continue;
|
||||
}
|
||||
|
||||
const rvals = needsAbacParsing.has(props.modelKind) ? parseABACRequest(n) : n.split(',').map(n => n.trim());
|
||||
result.push(await e.enforce(...rvals));
|
||||
}
|
||||
|
||||
const stopTime = performance.now();
|
||||
|
||||
props.onResponse(<Echo>{'Done in ' + ((stopTime - startTime) / 1000.0).toFixed(2) + 's'}</Echo>);
|
||||
props.onResponse(result);
|
||||
} catch (e) {
|
||||
props.onResponse(<Echo type={'error'}>{e.message}</Echo>);
|
||||
props.onResponse([]);
|
||||
}
|
||||
}
|
||||
|
||||
const RunTest = (props: RunTestProps) => {
|
||||
return (
|
||||
<Button
|
||||
style={{ marginRight: 8 }}
|
||||
onClick={async () => {
|
||||
const startTime = performance.now();
|
||||
const result = [];
|
||||
try {
|
||||
const e = await newEnforcer(newModel(props.model), props.policy ? new StringAdapter(props.policy) : undefined);
|
||||
|
||||
const fnString = props.fn;
|
||||
if (fnString) {
|
||||
try {
|
||||
const fns: any = {};
|
||||
// eslint-disable-next-line
|
||||
eval(`${fnString}`);
|
||||
if (fns) {
|
||||
Object.keys(fns).forEach(key => e.addFunction(key, fns[key]));
|
||||
}
|
||||
} catch (e) {
|
||||
props.onResponse(<Echo>Please check syntax in Custom Function Editor.</Echo>);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const requests = props.request.split('\n');
|
||||
|
||||
for (const n of requests) {
|
||||
const line = n.trim();
|
||||
if (!line) {
|
||||
result.push('# ignore');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] === '#') {
|
||||
result.push('# ignore');
|
||||
continue;
|
||||
}
|
||||
|
||||
const rvals = needsAbacParsing.has( props.modelKind) ? parseABACRequest(n) : n.split(',').map(n => n.trim());
|
||||
result.push(await e.enforce(...rvals));
|
||||
}
|
||||
|
||||
const stopTime = performance.now();
|
||||
|
||||
props.onResponse(<Echo>{'Done in ' + ((stopTime - startTime) / 1000.0).toFixed(2) + 's'}</Echo>);
|
||||
props.onResponse(result);
|
||||
} catch (e) {
|
||||
props.onResponse(<Echo type={'error'}>{e.message}</Echo>);
|
||||
props.onResponse([]);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button style={{ marginRight: 8 }} onClick={() => enforcer(props)}>
|
||||
RUN THE TEST
|
||||
</Button>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { getSelectedModel, setSelectedModel } from './persist';
|
||||
import { ModelKind, example } from './casbin-mode/example';
|
||||
|
||||
interface SelectModelProps {
|
||||
onChange: (value: string) => void;
|
||||
|
@ -18,20 +19,11 @@ const SelectModel = (props: SelectModelProps) => {
|
|||
<option value="" disabled>
|
||||
Select your model
|
||||
</option>
|
||||
<option value="basic">ACL</option>
|
||||
<option value="basic_with_root">ACL with superuser</option>
|
||||
<option value="basic_without_resources">ACL without resources</option>
|
||||
<option value="basic_without_users">ACL without users</option>
|
||||
<option value="rbac">RBAC</option>
|
||||
<option value="rbac_with_resource_roles">RBAC with resource roles</option>
|
||||
<option value="rbac_with_domains">RBAC with domains/tenants</option>
|
||||
<option value="rbac_with_deny">RBAC with deny-override</option>
|
||||
<option value="abac">ABAC</option>
|
||||
<option value="abac_with_policy_rule">ABAC with policy rule</option>
|
||||
<option value="keymatch">RESTful (KeyMatch)</option>
|
||||
<option value="keymatch2">RESTful (KeyMatch2)</option>
|
||||
<option value="ipmatch">IP match</option>
|
||||
<option value="priority">Priority</option>
|
||||
{Object.keys(example).map(n => (
|
||||
<option key={n} value={n}>
|
||||
{example[n as ModelKind].name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Button, Echo } from '../ui';
|
||||
import { Config } from 'casbin/lib/config';
|
||||
import { Config } from 'casbin';
|
||||
|
||||
interface SyntaxProps {
|
||||
model: string;
|
||||
|
@ -14,7 +14,7 @@ const Syntax = (props: SyntaxProps) => {
|
|||
onClick={() => {
|
||||
try {
|
||||
Config.newConfigFromText(props.model);
|
||||
props.onResponse(<Echo>passed</Echo>);
|
||||
props.onResponse(<Echo>Passed</Echo>);
|
||||
} catch (e) {
|
||||
props.onResponse(<Echo type={'error'}>{e.message}</Echo>);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue