Repository: casbin/casbin
Pull request #601 (2020-09-14 19:07:56)

feat: Add Domain for some func
Fix: https://github.com/casbin/casbin/issues/598


Patch:
diff --git a/README.md b/README.md
index 142ed62..6e512bc 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Casbin
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/casbin/lobby)
 [![Sourcegraph](https://sourcegraph.com/github.com/casbin/casbin/-/badge.svg)](https://sourcegraph.com/github.com/casbin/casbin?badge)
 
-**News**: still worry about how to write the correct Casbin policy? ``Casbin online editor`` is coming to help! Try it at: https://casbin.org/editor/
+**News**: still worry about how to write the correct Casbin policy? ``Casbin online editor`` is coming to help! Try it at: http://casbin.org/editor/
 
 ![casbin Logo](casbin-logo.png)
 
diff --git a/enforcer_interface.go b/enforcer_interface.go
index e392ae7..dbd7f56 100644
--- a/enforcer_interface.go
+++ b/enforcer_interface.go
@@ -63,18 +63,18 @@ type IEnforcer interface {
 	/* RBAC API */
 	GetRolesForUser(name string, domain ...string) ([]string, error)
 	GetUsersForRole(name string, domain ...string) ([]string, error)
-	HasRoleForUser(name string, role string) (bool, error)
-	AddRoleForUser(user string, role string) (bool, error)
+	HasRoleForUser(name string, role string, domain ...string) (bool, error)
+	AddRoleForUser(user string, role string, domain ...string) (bool, error)
 	AddPermissionForUser(user string, permission ...string) (bool, error)
 	DeletePermissionForUser(user string, permission ...string) (bool, error)
 	DeletePermissionsForUser(user string) (bool, error)
-	GetPermissionsForUser(user string) [][]string
+	GetPermissionsForUser(user string, domain ...string) [][]string
 	HasPermissionForUser(user string, permission ...string) bool
 	GetImplicitRolesForUser(name string, domain ...string) ([]string, error)
 	GetImplicitPermissionsForUser(user string, domain ...string) ([][]string, error)
 	GetImplicitUsersForPermission(permission ...string) ([]string, error)
-	DeleteRoleForUser(user string, role string) (bool, error)
-	DeleteRolesForUser(user string) (bool, error)
+	DeleteRoleForUser(user string, role string, domain ...string) (bool, error)
+	DeleteRolesForUser(user string, domain ...string) (bool, error)
 	DeleteUser(user string) (bool, error)
 	DeleteRole(role string) (bool, error)
 	DeletePermission(permission ...string) (bool, error)
diff --git a/rbac_api.go b/rbac_api.go
index f034ed1..bbbce7d 100644
--- a/rbac_api.go
+++ b/rbac_api.go
@@ -15,8 +15,7 @@
 package casbin
 
 import (
-	"errors"
-
+	"github.com/casbin/casbin/v2/errors"
 	"github.com/casbin/casbin/v2/util"
 )
 
@@ -33,8 +32,8 @@ func (e *Enforcer) GetUsersForRole(name string, domain ...string) ([]string, err
 }
 
 // HasRoleForUser determines whether a user has a role.
-func (e *Enforcer) HasRoleForUser(name string, role string) (bool, error) {
-	roles, err := e.GetRolesForUser(name)
+func (e *Enforcer) HasRoleForUser(name string, role string, domain ...string) (bool, error) {
+	roles, err := e.GetRolesForUser(name, domain...)
 	if err != nil {
 		return false, err
 	}
@@ -51,36 +50,44 @@ func (e *Enforcer) HasRoleForUser(name string, role string) (bool, error) {
 
 // AddRoleForUser adds a role for a user.
 // Returns false if the user already has the role (aka not affected).
-func (e *Enforcer) AddRoleForUser(user string, role string) (bool, error) {
-	return e.AddGroupingPolicy(user, role)
+func (e *Enforcer) AddRoleForUser(user string, role string, domain ...string) (bool, error) {
+	args := []string{user, role}
+	args = append(args, domain...)
+	return e.AddGroupingPolicy(args)
 }
 
 // AddRolesForUser adds roles for a user.
 // Returns false if the user already has the roles (aka not affected).
-func (e *Enforcer) AddRolesForUser(user string, roles []string) (bool, error) {
-	f := false
-	for _, r := range roles {
-		b, err := e.AddGroupingPolicy(user, r)
-		if err != nil {
-			return false, err
-		}
-		if b {
-			f = true
-		}
+func (e *Enforcer) AddRolesForUser(user string, roles []string, domain ...string) (bool, error) {
+	var rules [][]string
+	for _, role := range roles {
+		rule := []string{user, role}
+		rule = append(rule, domain...)
+		rules = append(rules, rule)
 	}
-	return f, nil
+	return e.AddGroupingPolicies(rules)
 }
 
 // DeleteRoleForUser deletes a role for a user.
 // Returns false if the user does not have the role (aka not affected).
-func (e *Enforcer) DeleteRoleForUser(user string, role string) (bool, error) {
-	return e.RemoveGroupingPolicy(user, role)
+func (e *Enforcer) DeleteRoleForUser(user string, role string, domain ...string) (bool, error) {
+	args := []string{user, role}
+	args = append(args, domain...)
+	return e.RemoveGroupingPolicy(args)
 }
 
 // DeleteRolesForUser deletes all roles for a user.
 // Returns false if the user does not have any roles (aka not affected).
-func (e *Enforcer) DeleteRolesForUser(user string) (bool, error) {
-	return e.RemoveFilteredGroupingPolicy(0, user)
+func (e *Enforcer) DeleteRolesForUser(user string, domain ...string) (bool, error) {
+	var args []string
+	if len(domain) == 0 {
+		args = []string{user}
+	} else if len(domain) > 1 {
+		return false, errors.ERR_DOMAIN_PARAMETER
+	} else {
+		args = []string{user, "", domain[0]}
+	}
+	return e.RemoveFilteredGroupingPolicy(0, args...)
 }
 
 // DeleteUser deletes a user.
@@ -134,8 +141,10 @@ func (e *Enforcer) DeletePermissionsForUser(user string) (bool, error) {
 }
 
 // GetPermissionsForUser gets permissions for a user or role.
-func (e *Enforcer) GetPermissionsForUser(user string) [][]string {
-	return e.GetFilteredPolicy(0, user)
+func (e *Enforcer) GetPermissionsForUser(user string, domain ...string) [][]string {
+	args := []string{user}
+	args = append(args, domain...)
+	return e.GetFilteredPolicy(0, args...)
 }
 
 // HasPermissionForUser determines whether a user has a permission.
@@ -196,21 +205,11 @@ func (e *Enforcer) GetImplicitPermissionsForUser(user string, domain ...string)
 
 	roles = append([]string{user}, roles...)
 
-	withDomain := false
-	if len(domain) == 1 {
-		withDomain = true
-	} else if len(domain) > 1 {
-		return nil, errors.New("domain should be 1 parameter")
-	}
-
 	var res [][]string
 	var permissions [][]string
 	for _, role := range roles {
-		if withDomain {
-			permissions = e.GetPermissionsForUserInDomain(role, domain[0])
-		} else {
-			permissions = e.GetPermissionsForUser(role)
-		}
+		permissions = e.GetPermissionsForUser(role, domain...)
+
 		res = append(res, permissions...)
 	}
 
diff --git a/rbac_api_synced.go b/rbac_api_synced.go
index 5f79315..a62fc52 100644
--- a/rbac_api_synced.go
+++ b/rbac_api_synced.go
@@ -29,34 +29,34 @@ func (e *SyncedEnforcer) GetUsersForRole(name string, domain ...string) ([]strin
 }
 
 // HasRoleForUser determines whether a user has a role.
-func (e *SyncedEnforcer) HasRoleForUser(name string, role string) (bool, error) {
+func (e *SyncedEnforcer) HasRoleForUser(name string, role string, domain ...string) (bool, error) {
 	e.m.RLock()
 	defer e.m.RUnlock()
-	return e.Enforcer.HasRoleForUser(name, role)
+	return e.Enforcer.HasRoleForUser(name, role, domain...)
 }
 
 // AddRoleForUser adds a role for a user.
 // Returns false if the user already has the role (aka not affected).
-func (e *SyncedEnforcer) AddRoleForUser(user string, role string) (bool, error) {
+func (e *SyncedEnforcer) AddRoleForUser(user string, role string, domain ...string) (bool, error) {
 	e.m.Lock()
 	defer e.m.Unlock()
-	return e.Enforcer.AddRoleForUser(user, role)
+	return e.Enforcer.AddRoleForUser(user, role, domain ...)
 }
 
 // DeleteRoleForUser deletes a role for a user.
 // Returns false if the user does not have the role (aka not affected).
-func (e *SyncedEnforcer) DeleteRoleForUser(user string, role string) (bool, error) {
+func (e *SyncedEnforcer) DeleteRoleForUser(user string, role string, domain ...string) (bool, error) {
 	e.m.Lock()
 	defer e.m.Unlock()
-	return e.Enforcer.DeleteRoleForUser(user, role)
+	return e.Enforcer.DeleteRoleForUser(user, role, domain ...)
 }
 
 // DeleteRolesForUser deletes all roles for a user.
 // Returns false if the user does not have any roles (aka not affected).
-func (e *SyncedEnforcer) DeleteRolesForUser(user string) (bool, error) {
+func (e *SyncedEnforcer) DeleteRolesForUser(user string, domain ...string) (bool, error) {
 	e.m.Lock()
 	defer e.m.Unlock()
-	return e.Enforcer.DeleteRolesForUser(user)
+	return e.Enforcer.DeleteRolesForUser(user, domain ...)
 }
 
 // DeleteUser deletes a user.
@@ -108,10 +108,10 @@ func (e *SyncedEnforcer) DeletePermissionsForUser(user string) (bool, error) {
 }
 
 // GetPermissionsForUser gets permissions for a user or role.
-func (e *SyncedEnforcer) GetPermissionsForUser(user string) [][]string {
+func (e *SyncedEnforcer) GetPermissionsForUser(user string, domain ...string) [][]string {
 	e.m.RLock()
 	defer e.m.RUnlock()
-	return e.Enforcer.GetPermissionsForUser(user)
+	return e.Enforcer.GetPermissionsForUser(user, domain ...)
 }
 
 // HasPermissionForUser determines whether a user has a permission.


Test patch:
diff --git a/rbac_api_test.go b/rbac_api_test.go
index 7e3b2ed..3448236 100644
--- a/rbac_api_test.go
+++ b/rbac_api_test.go
@@ -55,9 +55,9 @@ func testGetUsers(t *testing.T, e *Enforcer, res []string, name string, domain .
 	}
 }
 
-func testHasRole(t *testing.T, e *Enforcer, name string, role string, res bool) {
+func testHasRole(t *testing.T, e *Enforcer, name string, role string, res bool, domain ...string) {
 	t.Helper()
-	myRes, err := e.HasRoleForUser(name, role)
+	myRes, err := e.HasRoleForUser(name, role, domain...)
 	if err != nil {
 		t.Error("HasRoleForUser returned an error: ", err.Error())
 	}
@@ -127,9 +127,62 @@ func TestRoleAPI(t *testing.T) {
 	testEnforce(t, e, "bob", "data2", "write", true)
 }
 
+func TestRoleAPI_Domains(t *testing.T) {
+	e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv")
+
+	testHasRole(t, e, "alice", "admin", true, "domain1")
+	testHasRole(t, e, "alice", "admin", false, "domain2")
+	testGetRoles(t, e, []string{"admin"}, "alice", "domain1")
+	testGetRoles(t, e, []string{}, "bob", "domain1")
+	testGetRoles(t, e, []string{}, "admin", "domain1")
+	testGetRoles(t, e, []string{}, "non_exist", "domain1")
+	testGetRoles(t, e, []string{}, "alice", "domain2")
+	testGetRoles(t, e, []string{"admin"}, "bob", "domain2")
+	testGetRoles(t, e, []string{}, "admin", "domain2")
+	testGetRoles(t, e, []string{}, "non_exist", "domain2")
+
+	_, _ = e.DeleteRoleForUser("alice", "admin", "domain1")
+	_, _ = e.AddRoleForUser("bob", "admin", "domain1")
+
+	testGetRoles(t, e, []string{}, "alice", "domain1")
+	testGetRoles(t, e, []string{"admin"}, "bob", "domain1")
+	testGetRoles(t, e, []string{}, "admin", "domain1")
+	testGetRoles(t, e, []string{}, "non_exist", "domain1")
+	testGetRoles(t, e, []string{}, "alice", "domain2")
+	testGetRoles(t, e, []string{"admin"}, "bob", "domain2")
+	testGetRoles(t, e, []string{}, "admin", "domain2")
+	testGetRoles(t, e, []string{}, "non_exist", "domain2")
+
+	_, _ = e.AddRoleForUser("alice", "admin", "domain1")
+	_, _ = e.DeleteRolesForUser("bob", "domain1")
+
+	testGetRoles(t, e, []string{"admin"}, "alice", "domain1")
+	testGetRoles(t, e, []string{}, "bob", "domain1")
+	testGetRoles(t, e, []string{}, "admin", "domain1")
+	testGetRoles(t, e, []string{}, "non_exist", "domain1")
+	testGetRoles(t, e, []string{}, "alice", "domain2")
+	testGetRoles(t, e, []string{"admin"}, "bob", "domain2")
+	testGetRoles(t, e, []string{}, "admin", "domain2")
+	testGetRoles(t, e, []string{}, "non_exist", "domain2")
+
+	_, _ = e.AddRolesForUser("bob", []string{"admin", "admin1", "admin2"}, "domain1")
+
+	testGetRoles(t, e, []string{"admin", "admin1", "admin2"}, "bob", "domain1")
+
+	testGetPermissions(t, e, "admin", [][]string{{"admin", "domain1", "data1", "read"}, {"admin", "domain1", "data1", "write"}}, "domain1")
+	testGetPermissions(t, e, "admin", [][]string{{"admin", "domain2", "data2", "read"}, {"admin", "domain2", "data2", "write"}}, "domain2")
+
+}
+
 func TestEnforcer_AddRolesForUser(t *testing.T) {
 	e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
 
+	_, _ = e.AddRolesForUser("alice", []string{"data1_admin", "data2_admin", "data3_admin"})
+	// The "alice" already has "data2_admin" , it will be return false. So "alice" just has "data2_admin".
+	testGetRoles(t, e, []string{"data2_admin"}, "alice")
+	// delete role
+	_, _ = e.DeleteRoleForUser("alice", "data2_admin")
+
 	_, _ = e.AddRolesForUser("alice", []string{"data1_admin", "data2_admin", "data3_admin"})
 	testGetRoles(t, e, []string{"data1_admin", "data2_admin", "data3_admin"}, "alice")
 	testEnforce(t, e, "alice", "data1", "read", true)
@@ -137,9 +190,9 @@ func TestEnforcer_AddRolesForUser(t *testing.T) {
 	testEnforce(t, e, "alice", "data2", "write", true)
 }
 
-func testGetPermissions(t *testing.T, e *Enforcer, name string, res [][]string) {
+func testGetPermissions(t *testing.T, e *Enforcer, name string, res [][]string, domain ...string) {
 	t.Helper()
-	myRes := e.GetPermissionsForUser(name)
+	myRes := e.GetPermissionsForUser(name, domain...)
 	t.Log("Permissions for ", name, ": ", myRes)
 
 	if !util.Array2DEquals(res, myRes) {