Repository: casbin/casbin
Pull request #497 (2020-06-17 05:27:08)

feat: add a rule of effect "Allow-override"
fix: #496 

coveralls: 
[![Coverage Status](https://coveralls.io/builds/31502870/badge)](https://coveralls.io/builds/31502870)

Coverage decreased (-0.3%) to 74.818% when pulling **c07ae2dbcdf0bf39dda56204ea25979319d6986d on ticktap:master** into **4e5c2cebc31ee9fb22b5ebf6188aaec4b9b3285e on casbin:master**.

hsluoyz: @nodece @GopherJ @dovics please review.
hsluoyz: @ticktap why don't use priority model?
ticktap: > @ticktap why don't use priority model?

it can not allow when I omit allow policy, priority default result is false.
nodece: @ticktap I think `priority(p_eft) || allow` can meet your need?
hsluoyz: @ticktap you can add a policy to allow all, put it at the last of the list.
ticktap: > @ticktap you can add a policy to allow all, put it at the last of the list.

It worked for me. But I think it is necessary to add "Allow-override".
nodece: @hsluoyz  Could you review the PR?
hsluoyz: @ticktap please fix the checks:

![image](https://user-images.githubusercontent.com/3787410/89043604-4c22ab00-d37b-11ea-8127-8254dfb7e91e.png)

nodece: @hsluoyz if you are approved, I will merge it to master.
hsluoyz: @nodece please let @ticktap fix the checks:

![image](https://user-images.githubusercontent.com/3787410/89043604-4c22ab00-d37b-11ea-8127-8254dfb7e91e.png)

ticktap: Sorry, I'm not sure how to fix these checks. @hsluoyz any tips?
hsluoyz: @ticktap see: https://github.com/zeke/semantic-pull-requests

Patch:
diff --git a/effect/default_effector.go b/effect/default_effector.go
index 8fe7f16..7fd4116 100644
--- a/effect/default_effector.go
+++ b/effect/default_effector.go
@@ -59,6 +59,17 @@ func (e *DefaultEffector) MergeEffects(expr string, effects []Effect, results []
 				break
 			}
 		}
+	} else if expr == "some(where (p_eft == allow)) || !some(where (p_eft == deny))" {
+		result = true
+		for i, eft := range effects {
+			if eft == Allow {
+				result = true
+				explainIndex = i
+				break
+			} else if eft == Deny {
+				result = false
+			}
+		}
 	} else if expr == "priority(p_eft) || deny" {
 		result = false
 		for i, eft := range effects {
diff --git a/frontend.go b/frontend.go
new file mode 100644
index 0000000..ce37aaa
--- /dev/null
+++ b/frontend.go
@@ -0,0 +1,32 @@
+// Copyright 2020 The casbin Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package casbin
+
+import (
+	"encoding/json"
+)
+
+func CasbinJsGetPermissionForUser(e *Enforcer, user string) ([]byte, error) {
+	policy, err := e.GetImplicitPermissionsForUser(user)
+	if err != nil {
+		return nil, err
+	}
+	permission := make(map[string][]string)
+	for i := 0; i < len(policy); i++ {
+		permission[policy[i][2]] = append(permission[policy[i][2]], policy[i][1])
+	}
+	b, _ := json.Marshal(permission)
+	return b, nil
+}
diff --git a/management_api.go b/management_api.go
index 3d60ed2..48c9810 100644
--- a/management_api.go
+++ b/management_api.go
@@ -215,7 +215,7 @@ func (e *Enforcer) AddGroupingPolicy(params ...interface{}) (bool, error) {
 	return e.AddNamedGroupingPolicy("g", params...)
 }
 
-// AddGroupingPolicies adds role inheritance rulea to the current policy.
+// AddGroupingPolicies adds role inheritance rules to the current policy.
 // If the rule already exists, the function returns false for the corresponding policy rule and the rule will not be added.
 // Otherwise the function returns true for the corresponding policy rule by adding the new rule.
 func (e *Enforcer) AddGroupingPolicies(rules [][]string) (bool, error) {
@@ -254,7 +254,7 @@ func (e *Enforcer) RemoveGroupingPolicy(params ...interface{}) (bool, error) {
 	return e.RemoveNamedGroupingPolicy("g", params...)
 }
 
-// RemoveGroupingPolicies removes role inheritance rulea from the current policy.
+// RemoveGroupingPolicies removes role inheritance rules from the current policy.
 func (e *Enforcer) RemoveGroupingPolicies(rules [][]string) (bool, error) {
 	return e.RemoveNamedGroupingPolicies("g", rules)
 }


Test patch:
diff --git a/frontend_test.go b/frontend_test.go
new file mode 100644
index 0000000..2766879
--- /dev/null
+++ b/frontend_test.go
@@ -0,0 +1,93 @@
+// Copyright 2020 The casbin Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package casbin
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+func contains(arr []string, target string) bool {
+	for _, item := range arr {
+		if item == target {
+			return true
+		}
+	}
+	return false
+}
+
+func TestCasbinJsGetPermissionForUser(t *testing.T) {
+	e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
+	if err != nil {
+		panic(err)
+	}
+	target_str, _ := CasbinJsGetPermissionForUser(e, "alice")
+	t.Log("GetPermissionForUser Alice", string(target_str))
+	alice_target := make(map[string][]string)
+	err = json.Unmarshal(target_str, &alice_target)
+	if err != nil {
+		t.Errorf("Test error: %s", err)
+	}
+	perm, ok := alice_target["read"]
+	if !ok {
+		t.Errorf("Test error: Alice doesn't have read permission")
+	}
+	if !contains(perm, "data1") {
+		t.Errorf("Test error: Alice cannot read data1")
+	}
+	if !contains(perm, "data2") {
+		t.Errorf("Test error: Alice cannot read data2")
+	}
+	perm, ok = alice_target["write"]
+	if !ok {
+		t.Errorf("Test error: Alice doesn't have write permission")
+	}
+	if contains(perm, "data1") {
+		t.Errorf("Test error: Alice can write data1")
+	}
+	if !contains(perm, "data2") {
+		t.Errorf("Test error: Alice cannot write data2")
+	}
+
+	target_str, _ = CasbinJsGetPermissionForUser(e, "bob")
+	t.Log("GetPermissionForUser Bob", string(target_str))
+	bob_target := make(map[string][]string)
+	err = json.Unmarshal(target_str, &bob_target)
+	if err != nil {
+		t.Errorf("Test error: %s", err)
+	}
+	_, ok = bob_target["read"]
+	if ok {
+		t.Errorf("Test error: Bob has read permission")
+	}
+	perm, ok = bob_target["write"]
+	if !ok {
+		t.Errorf("Test error: Bob doesn't have permission")
+	}
+	if !contains(perm, "data2") {
+		t.Errorf("Test error: Bob cannot write data2")
+	}
+	if contains(perm, "data1") {
+		t.Errorf("Test error: Bob can write data1")
+	}
+	if contains(perm, "data_not_exist") {
+		t.Errorf("Test error: Bob can access a non-existing data")
+	}
+
+	_, ok = bob_target["rm_rf"]
+	if ok {
+		t.Errorf("Someone can have a non-existing action (rm -rf)")
+	}
+}