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

[Question] - Please help on defining casbin model and policy for following use case. #1246

Open
sujit-baniya opened this issue May 5, 2023 · 4 comments

Comments

@sujit-baniya
Copy link

I have a use case where a role is assigned to an entity id on a service for a specific domain. the policy would look like this.

p, admin,abc.com,medical-coding,work-item,1, /blog, GET
p, super_admin,*,*,*,*,/user,POST
p, account_manager,abc.com,medical-coding,*,*,/provider, POST

g, alice, admin, abc.com,medical-coding,work-item,1
g, john, super_admin,*,*,*,*
g, doe, account_manager,abc.com,medical-coding,*,*

Here, I'm unsure how to define a model to match/enforce requests based on the sample policy provided above.
I've tried to refactor the following model to make it work for the policy.

[request_definition]
r = sub, dom, obj, act

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

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

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

[matchers]
m = (g(r.sub, p.sub, "*") || g(r.sub, p.sub, get_domain(r.dom) + ":*") || g(r.sub, p.sub, get_domain(r.dom)) || g2(r.dom, p.dom)) && keyMatch4(get_domain(r.dom), get_domain(p.dom)) && keyMatch4(get_work(r.dom), get_work(p.dom)) && keyMatch4(r.obj, p.obj) && keyMatch4(r.act, p.act)

I'm not able to refactor the model. Please suggest how I could make it work.

@casbin-bot
Copy link
Member

@tangyang9464 @JalinWang

@hsluoyz
Copy link
Member

hsluoyz commented May 6, 2023

@PokIsemaine

@PokIsemaine
Copy link
Member

Hi, @sujit-baniya It looks like there are several issues, and I cannot help you solve them all at once, but don't worry, I will help you sort them out gradually.

First, your model configuration format should correspond to your actual policy:

[policy_definition]
p = sub, dom, obj, act
p, admin,abc.com,medical-coding,work-item,1, /blog, GET
p, super_admin,*,*,*,*,/user,POST
p, account_manager,abc.com,medical-coding,*,*,/provider, POST

The following figure shows the actual correspondence, which obviously does not match your expectations. One field should correspond to one string, and you can try writing multiple policies. Since I am not sure about the actual meaning of each field, you can make some modifications first and reply to me below, and then we can further correct them.

image

@sujit-baniya
Copy link
Author

@PokIsemaine Thank you for your response. I'm able to fix the permission by using following model and policy

[request_definition]
r = user, domain, resource, action, attributes

[policy_definition]
p = user, domain, eft, resource, action, conditions

[role_definition]
g = _, _, _

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

[matchers]
m = g(r.user, p.user, r.domain) && keyMatch2(r.domain, p.domain) && keyMatch2(r.resource, p.resource) && isMatch(r.attributes, p.conditions) && keyMatch2(r.action, p.action)
p, finance, domainHere, allow, expense, read, "{ service: work-item, db: golang }"
p, 123-413-13, domainHere, deny, expense, read, "{ id: 10 }"
p, financePerson, domainHere, allow, *, write, "{ service: ""*"", db: ""*"" }"
g, finance, financePerson, domainHere

func main() {
	perm, err := permission.Default(permission.Config{
		Model:  "model.conf",
		Policy: "policy.csv",
	})
	if err != nil {
		fmt.Println("error: ")
		panic(err)
	}
	perm.AddFunction("isMatch", func(args ...interface{}) (interface{}, error) {
		switch attributes := args[0].(type) {
		case map[string]any:
			switch condition := args[1].(type) {
			case map[string]any:
				return IsMatch(attributes, condition)
			case string:
				t, err := getMapFromString(condition)
				if err != nil || len(t) == 0 {
					return true, nil
				}
				return IsMatch(attributes, t)
			}
		case string:
			if attributes != "" {
				attr, err := getMapFromString(attributes)
				if err != nil {
					return false, nil
				}
				switch condition := args[1].(type) {
				case map[string]any:
					return IsMatch(attr, condition)
				case string:
					t, err := getMapFromString(condition)
					if err != nil {
						return true, nil
					}
					if len(t) == 0 {
						return str.EqualFold(attributes, condition), nil
					}
					return IsMatch(attr, t)
				}
			}
		}
		return false, nil
	})
	fmt.Println(perm.EnforceEx("finance", "domainHere", "/expense/1", "write", map[string]any{
		"service": "*",
		"db":      "golang",
	}))
}

It's working as intended. Now the thing I'm stuck is on group. Can you please suggest how could I fix g to include attributes and conditions

Basically I'm trying to assign a role to user for a domain with service and entity id

For .e.g

g, joe, finance, domainHere, "{service: medical-coding, entity: work-item, entity_id: 2 }"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants