Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suggestion: add YAML support for model #432

Closed
nodece opened this issue Apr 22, 2020 · 27 comments
Closed

suggestion: add YAML support for model #432

nodece opened this issue Apr 22, 2020 · 27 comments
Assignees

Comments

@nodece
Copy link
Member

nodece commented Apr 22, 2020

YAML is a human friendly data serialization standard for all programming languages.

It can help users to write and verify the model .

How to help users to write and verify the model?

We need to write the YAML schema then IDE can provides hints based upon YAML schema provided to helps user write schema efficiently.

Please refer to https://dzone.com/articles/two-ways-configuration-documentation-with-springnb to write YAML schema then publish to https://github.com/SchemaStore/schemastore.

@hsluoyz
Copy link
Member

hsluoyz commented Apr 22, 2020

We can add support for YAML but do not break current API.

@hsluoyz hsluoyz self-assigned this Apr 22, 2020
@nodece
Copy link
Member Author

nodece commented Apr 22, 2020

Here want to collection some YAML config.

@nodece
Copy link
Member Author

nodece commented Apr 22, 2020

consider multiple p, e and m, You can refer to casbin/casbin-rs#123

@GopherJ
Copy link
Member

GopherJ commented Apr 22, 2020

@hsluoyz @nodece I also think we should move to YAML/TOML because with ini we will have limited information, we don't know how to indicate for example m1 should use e2.

Also we should maybe find a way to indicate which p will we use for which m because otherwise we will need to do something like : casbin/casbin-rs#123, we will need to extract_ptype_from_matcher.

To implement multiple p, e, m, we should provide maxmum information when we load model from file, otherwise we will need to do it during enforce which causes bench downgrade.

@GopherJ
Copy link
Member

GopherJ commented Apr 22, 2020

To summary:

  1. we need to find a way to express: m[a] should use e[b] as effects merge strategy.
  2. we need to find a way to express: m[a] has used p[b], one matcher can only have one kind of ptype, otherwise panic
  3. we need to find a way to avoid write: p2, p3, p4, p5...., e1, e2, e3, e4 and make it possible to be customlized by users, because if users have two types of matchers/effects/policies, they often would like to make every type of matcher/effect/policy has a meaningful name instead of just m1, m2, e1, e2, p1, p2

Also:

If we would like to use matcher in other matchers, we also need to find a better way to store this information into model. Like m3 = m && !m2, we should at least have the information that m3 will relies on m and m2. This will help to improve bench.

Image the following matchers:

m = r.sub == p.sub
m2 = r.dom == p.dom
m3 = r.obj == p.obj

m5 = m && m2
m6 = m3 && m5

When we calculate m, if we know it doesn't rely on the result of any other matchers, we can then calculate just its value and ignore m2, m3, m5, m6.

When we calculate m5, if we know it relies on the result of m and m2, we can then calculate m, m2 and ignore m6

If we would like to use matcher in other matchers, we also need to find a better way to store this information into model. Like m3 = m && !m2, we should at least have the information that m3 will relies on m and m2. This will help to improve bench.

@hsluoyz
Copy link
Member

hsluoyz commented Apr 23, 2020

@GopherJ

we need to find a way to express: m[a] should use e[b] as effects merge strategy.
we need to find a way to express: m[a] has used p[b], one matcher can only have one kind of ptype, otherwise panic

m2 maps to e2 and p2.
m["admin"] maps to e["admin"] and p["admin"]

we need to find a way to avoid write: p2, p3, p4, p5...., e1, e2, e3, e4 and make it possible to be customlized by users, because if users have two types of matchers/effects/policies, they often would like to make every type of matcher/effect/policy has a meaningful name instead of just m1, m2, e1, e2, p1, p2

We will support both p, p2, p3... and p["basic"], p["admin"], ...

If we would like to use matcher in other matchers, we also need to find a better way to store this information into model. Like m3 = m && !m2, we should at least have the information that m3 will relies on m and m2. This will help to improve bench.

Matchers can be referred as m2 or m["admin"] in another matcher.

@GopherJ
Copy link
Member

GopherJ commented Apr 23, 2020

@hsluoyz

m2 maps to e2 and p2, m["admin"] maps to e["admin"] and p["admin"]

The latter is not supported yet, we also don't know which p are we using for m, if p2 should only be used in m2 it's better to panic when we load model instead of panic during enforce.

Matchers can be referred as m2 or m["admin"] in another matcher.

It requires knowing the reference relationshop, otherwise we will need to calculate every m by order. It'll no inefficient if the m doesn't rely on the others.

@nodece
Copy link
Member Author

nodece commented Apr 24, 2020

We provide a YAML config:

request_definition:
  - name: r
    token:
      - sub
      - obj
      - act

policy_definition:
  - name: p
    token:
      - sub_rule
      - obj
      - act

  - name: p2
    token:
      - sub_rule
      - obj
      - act

matchers:
  - name: m
    token: eval(p.sub_rule) && r.obj == p.obj && r.act == p.act
    effect: some(where (p.eft == allow))

  - name: m1
    token: eval(p.sub_rule) && r.obj == p.obj && r.act == p.act
    effect: some(where (p.eft == allow))

  - name: m2
    token: m && m1 && eval(p2.sub_rule) && r.obj == p2.obj && r.act == p2.act
    with:
      - m # Use matcher name is m
      - m1 # Use matcher name is m1
    effect: some(where (p.eft == allow)) 

It looks very complicated, but we support autocomplete, so easy.

@nodece
Copy link
Member Author

nodece commented Apr 24, 2020

Apr-23-2020 15-26-34

@GopherJ
Copy link
Member

GopherJ commented Apr 25, 2020

@nodece autocomplete can be useful only when we are turing-complete

@hsluoyz
Copy link
Member

hsluoyz commented May 4, 2020

How to be turing-complete?

@GopherJ
Copy link
Member

GopherJ commented May 5, 2020

@hsluoyz My idea on turing complete is:

  1. stop using p1, p2, p3... we always save sec + ptype + rules for persistence

  2. convert the whole model.conf to a function which accept request as arguments, every = is an assignment inside this function. matcher will be sub function which accepts policies as argument.

@GopherJ
Copy link
Member

GopherJ commented May 10, 2020

new basic_model conf example:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = p.some(x => m(x) == true)

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

should be converted to:

function enforce(req: string[]. policies: string[][]): boolean {
  let r = {};
  let p = [];

  let rtokens = ["sub", "obj", "act"];
  let ptokens = ["sub", "obj", "act"];

  function e(p: string[][]): boolean {
    return p.some(x => m(x) == true)
  }

  for (i, rtoken) in rokens {
    r[rtoken] = req[i];
  }

  for (i, rule) in policies {
    for (j, ptoken) in ptokens {
      let tmp = {};
      tmp[ptoken] = rule[j];
      p.push(tmp); 
    }
  }

  function m(p: string[]): boolean {
    return r.r.sub == p.sub && r.obj == p.obj && r.act == p.act
  }

  return e(p);
}

we just need to use evaluation engine to call this function with request

@GopherJ
Copy link
Member

GopherJ commented May 10, 2020

The advantage is that every assignment will be taken into account

@hsluoyz
Copy link
Member

hsluoyz commented May 10, 2020

How to dynamically generate such a function? Also govaluate can only evaluate expressions?

@GopherJ
Copy link
Member

GopherJ commented May 10, 2020

@hsluoyz

How to dynamically generate such a function? Also govaluate can only evaluate expressions?

I believe this can only be supported by a few expression evaluator, rhai will be able to support this type of thing.

If I managed to have a general idea, I can try on casbin-rs.

In my point of view, To support turing complete = making model.conf a script like writing code using programing language.

@hsluoyz
Copy link
Member

hsluoyz commented May 10, 2020

Your idea looks interesting. But:

  1. It's difficult to implement for static languages.
  2. More logic is put into evaluator. The speed will be slower.

But it's a nice try.

Maybe a minor improvement for now is to evaluate the effect like matcher too. Currently it's hard-coded.

@GopherJ
Copy link
Member

GopherJ commented May 10, 2020

@hsluoyz Yes, I think that can be a start, in my example we don't enforce_with_matcher but enforce_with_effect, effect gives the info which matcher shall we use.

@GopherJ
Copy link
Member

GopherJ commented May 10, 2020

@hsluoyz

More logic is put into evaluator. The speed will be slower.

General speaking it should be slower, but except of converting model.conf a real script, I cannot see how to achieve turing complete.

Let's gather more ideas and decide how to improve ~

@GopherJ
Copy link
Member

GopherJ commented May 10, 2020

@hsluoyz

It's difficult to implement for static languages.

This is often not the case, because many evaluators target at script language

@hsluoyz
Copy link
Member

hsluoyz commented May 14, 2020

How is evaluator like govaluate working? It's like Docker or run-time instruction translation?

And if we choose this function idea. Why not just re-write Casbin in Lua and embed a Lua interpreter for all languages?

@GopherJ
Copy link
Member

GopherJ commented May 14, 2020

@hsluoyz evaluator parses string as AST then use Recursive descent method to eval every part of expression.

Yes it's possible, I haven't used lua yet. but we definitly need some powerful script language interpreter.

Maybe that's why that person choosed to use python

@GopherJ
Copy link
Member

GopherJ commented May 14, 2020

@hsluoyz I just did a fibonacci test using rhai and rlua.

the result of fibonacci(20):

rlua is 23x faster than rhai:)

I may do more bench test this weekend

@hsluoyz
Copy link
Member

hsluoyz commented May 17, 2020

The number looks nice. Expecting your result.

@GopherJ
Copy link
Member

GopherJ commented May 17, 2020

@hsluoyz While thinking more, I think it can also be dangerous to use lua stuff, because it looks more like a real language, that means it may raise security issue since I haven't found how to limit user's input.

@schungx
Copy link

schungx commented May 27, 2020

rlua is 23x faster than rhai:)

AFAIK, Lua has a JIT. That's gonna make it fly!

that means it may raise security issue

Any time you jump out to C/C++, you break open the sand box and depends solely on the code quality of the external library. For a security-oriented project maybe not a good idea to trade performance with safety...

@hsluoyz
Copy link
Member

hsluoyz commented May 29, 2021

We have a Lua-Casbin now: https://github.com/casbin/lua-casbin

Closed here.

@hsluoyz hsluoyz closed this as completed May 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants