Casbin Forum runs on Casnode, the open-source Discourse-style forum. Try the Casnode demo →
Casbin Forum
1views
2users
1 minread

I went from this model:

const stringModel = `
[request_definition]
r = user, dom, obj, act, tag

[policy_definition]
p = role, dom, obj, act, tag

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

[role_definition]
g = _, _, _
g2 = _, _

[matchers]
m = g(r.user, p.role, r.tag) && g2(p.role, r.dom) && keyMatch(r.tag, p.tag) && keyMatch(r.act, p.act) && (keyMatch(r.obj, p.obj) || keyMatch2(r.obj, p.obj))
    `

func TestDefaultRbac(t *testing.T) {
    m, _ := model.NewModelFromString(stringModel)
    e, _ := casbin.NewEnforcer(m, false)

    e.AddPolicies([][]string{
        {"reader", "org1", "/project", "GET", "project_*"},
        {"editor", "org1", "/project", "DELETE", "project_*"},
        {"reader2", "org2", "/project", "GET", "project_*"},
    })

    e.AddNamedGroupingPolicies("g", [][]string{
        {"tom", "reader", "project_1"},
        {"tom", "reader", "project_2"},
        {"tom", "reader", "project_3"},
        {"tom", "editor", "project_5"},
        {"henk", "reader2", "project_6"},
    })

    e.AddNamedGroupingPolicies("g2", [][]string{
        {"reader", "org1"},
        {"reader2", "org2"},
        {"editor", "org1"},
    })

    enforcer := func(user, dom, obj, act, tag string, expect bool) {
        resp, _ := e.Enforce(user, dom, obj, act, tag)
        if resp != expect {
            t.Errorf("Response is for %s %s %s %s %s %t expected to be %t", user, dom, obj, act, tag, resp, expect)
        }
    }

    enforcer("tom", "org1", "/project", "GET", "project_1", true)
    enforcer("tom", "org1", "/project", "DELETE", "project_1", false)
    enforcer("tom", "org1", "/project", "DELETE", "project_5", true)
    enforcer("tom", "org2", "/project", "GET", "project_6", false)
    enforcer("henk", "org2", "/project", "GET", "project_6", true)
}

to this, I left out the whole org part since the roles will be unique per org and are therefore implicity tied to an org:


const stringModel2 = `
[request_definition]
r = user, obj, act, tag

[policy_definition]
p = role, obj, act, tag

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

[role_definition]
g = _, _, _

[matchers]
m = g(r.user, p.role, r.tag) && keyMatch(r.tag, p.tag) && keyMatch(r.act, p.act) && (keyMatch(r.obj, p.obj) || keyMatch2(r.obj, p.obj))
    `

func TestDefaultRbac2(t *testing.T) {
    m, _ := model.NewModelFromString(stringModel2)
    e, _ := casbin.NewEnforcer(m, false)

    e.AddPolicies([][]string{
        {"reader", "/project", "GET", "project_*"},
        {"editor", "/project", "DELETE", "project_*"},
        {"reader2", "/project", "GET", "project_*"},
    })

    e.AddNamedGroupingPolicies("g", [][]string{
        {"tom", "reader", "project_1"},
        {"tom", "reader", "project_2"},
        {"tom", "reader", "project_3"},
        {"tom", "editor", "project_5"},
        {"henk", "reader2", "project_6"},
    })

    enforcer := func(user, obj, act, tag string, expect bool) {
        resp, _ := e.Enforce(user, obj, act, tag)
        if resp != expect {
            t.Errorf("Response is for %s %s %s %s %t expected to be %t", user, obj, act, tag, resp, expect)
        }
    }

    enforcer("tom", "/project", "GET", "project_1", true)
    enforcer("tom", "/project", "DELETE", "project_1", false)
    enforcer("tom", "/project", "DELETE", "project_5", true)
    enforcer("tom", "/project", "GET", "project_6", false)
    enforcer("henk", "/project", "GET", "project_6", true)
}

Both do the same thing one is explicit with role + org combination and the other is implicit. E.g. reader is part of org1 and reader2 is part of org2

I plan to make a custom adapter https://casbin.org/docs/adapters/ that loads the filtered policy for each request and checks it.

that loads the filtered policy for each request and checks it. for endpoints that need it

1 / 2
May 2024