blob: 6d88eded175de0faaebdb920d9989686e67668b6 [file] [log] [blame]
// Copyright 2017 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 (
"fmt"
"log"
"sort"
"testing"
"github.com/casbin/casbin/v3/constant"
"github.com/casbin/casbin/v3/errors"
defaultrolemanager "github.com/casbin/casbin/v3/rbac/default-role-manager"
"github.com/casbin/casbin/v3/util"
)
func testGetRoles(t *testing.T, e *Enforcer, res []string, name string, domain ...string) {
t.Helper()
myRes, err := e.GetRolesForUser(name, domain...)
if err != nil {
t.Error("Roles for ", name, " could not be fetched: ", err.Error())
}
t.Log("Roles for ", name, ": ", myRes)
if !util.SetEquals(res, myRes) {
t.Error("Roles for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func testGetUsers(t *testing.T, e *Enforcer, res []string, name string, domain ...string) {
t.Helper()
myRes, err := e.GetUsersForRole(name, domain...)
switch err {
case nil:
break
case errors.ErrNameNotFound:
t.Log("No name found")
default:
t.Error("Users for ", name, " could not be fetched: ", err.Error())
}
t.Log("Users for ", name, ": ", myRes)
if !util.SetEquals(res, myRes) {
t.Error("Users for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func testHasRole(t *testing.T, e *Enforcer, name string, role string, res bool, domain ...string) {
t.Helper()
myRes, err := e.HasRoleForUser(name, role, domain...)
if err != nil {
t.Error("HasRoleForUser returned an error: ", err.Error())
}
t.Log(name, " has role ", role, ": ", myRes)
if res != myRes {
t.Error(name, " has role ", role, ": ", myRes, ", supposed to be ", res)
}
}
func TestRoleAPI(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
testGetRoles(t, e, []string{"data2_admin"}, "alice")
testGetRoles(t, e, []string{}, "bob")
testGetRoles(t, e, []string{}, "data2_admin")
testGetRoles(t, e, []string{}, "non_exist")
testHasRole(t, e, "alice", "data1_admin", false)
testHasRole(t, e, "alice", "data2_admin", true)
_, _ = e.AddRoleForUser("alice", "data1_admin")
testGetRoles(t, e, []string{"data1_admin", "data2_admin"}, "alice")
testGetRoles(t, e, []string{}, "bob")
testGetRoles(t, e, []string{}, "data2_admin")
_, _ = e.DeleteRoleForUser("alice", "data1_admin")
testGetRoles(t, e, []string{"data2_admin"}, "alice")
testGetRoles(t, e, []string{}, "bob")
testGetRoles(t, e, []string{}, "data2_admin")
_, _ = e.DeleteRolesForUser("alice")
testGetRoles(t, e, []string{}, "alice")
testGetRoles(t, e, []string{}, "bob")
testGetRoles(t, e, []string{}, "data2_admin")
_, _ = e.AddRoleForUser("alice", "data1_admin")
_, _ = e.DeleteUser("alice")
testGetRoles(t, e, []string{}, "alice")
testGetRoles(t, e, []string{}, "bob")
testGetRoles(t, e, []string{}, "data2_admin")
_, _ = e.AddRoleForUser("alice", "data2_admin")
testEnforce(t, e, "alice", "data1", "read", false)
testEnforce(t, e, "alice", "data1", "write", false)
testEnforce(t, e, "alice", "data2", "read", true)
testEnforce(t, e, "alice", "data2", "write", true)
testEnforce(t, e, "bob", "data1", "read", false)
testEnforce(t, e, "bob", "data1", "write", false)
testEnforce(t, e, "bob", "data2", "read", false)
testEnforce(t, e, "bob", "data2", "write", true)
_, _ = e.DeleteRole("data2_admin")
testEnforce(t, e, "alice", "data1", "read", false)
testEnforce(t, e, "alice", "data1", "write", false)
testEnforce(t, e, "alice", "data2", "read", false)
testEnforce(t, e, "alice", "data2", "write", false)
testEnforce(t, e, "bob", "data1", "read", false)
testEnforce(t, e, "bob", "data1", "write", false)
testEnforce(t, e, "bob", "data2", "read", false)
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)
testEnforce(t, e, "alice", "data2", "read", true)
testEnforce(t, e, "alice", "data2", "write", true)
}
func testGetPermissions(t *testing.T, e *Enforcer, name string, res [][]string, domain ...string) {
t.Helper()
myRes, err := e.GetPermissionsForUser(name, domain...)
if err != nil {
t.Error(err.Error())
}
t.Log("Permissions for ", name, ": ", myRes)
if !util.Array2DEquals(res, myRes) {
t.Error("Permissions for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func testHasPermission(t *testing.T, e *Enforcer, name string, permission []string, res bool) {
t.Helper()
myRes, err := e.HasPermissionForUser(name, permission...)
if err != nil {
t.Error(err.Error())
}
t.Log(name, " has permission ", util.ArrayToString(permission), ": ", myRes)
if res != myRes {
t.Error(name, " has permission ", util.ArrayToString(permission), ": ", myRes, ", supposed to be ", res)
}
}
func testGetNamedPermissionsForUser(t *testing.T, e *Enforcer, ptype string, name string, res [][]string, domain ...string) {
t.Helper()
myRes, err := e.GetNamedPermissionsForUser(ptype, name, domain...)
if err != nil {
t.Error(err.Error())
}
t.Log("Named permissions for ", name, ": ", myRes)
if !util.Array2DEquals(res, myRes) {
t.Error("Named permissions for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func TestPermissionAPI(t *testing.T) {
e, _ := NewEnforcer("examples/basic_without_resources_model.conf", "examples/basic_without_resources_policy.csv")
testEnforceWithoutUsers(t, e, "alice", "read", true)
testEnforceWithoutUsers(t, e, "alice", "write", false)
testEnforceWithoutUsers(t, e, "bob", "read", false)
testEnforceWithoutUsers(t, e, "bob", "write", true)
testGetPermissions(t, e, "alice", [][]string{{"alice", "read"}})
testGetPermissions(t, e, "bob", [][]string{{"bob", "write"}})
testHasPermission(t, e, "alice", []string{"read"}, true)
testHasPermission(t, e, "alice", []string{"write"}, false)
testHasPermission(t, e, "bob", []string{"read"}, false)
testHasPermission(t, e, "bob", []string{"write"}, true)
_, _ = e.DeletePermission("read")
testEnforceWithoutUsers(t, e, "alice", "read", false)
testEnforceWithoutUsers(t, e, "alice", "write", false)
testEnforceWithoutUsers(t, e, "bob", "read", false)
testEnforceWithoutUsers(t, e, "bob", "write", true)
_, _ = e.AddPermissionForUser("bob", "read")
testEnforceWithoutUsers(t, e, "alice", "read", false)
testEnforceWithoutUsers(t, e, "alice", "write", false)
testEnforceWithoutUsers(t, e, "bob", "read", true)
testEnforceWithoutUsers(t, e, "bob", "write", true)
_, _ = e.AddPermissionsForUser("jack",
[]string{"read"},
[]string{"write"})
testEnforceWithoutUsers(t, e, "jack", "read", true)
testEnforceWithoutUsers(t, e, "bob", "write", true)
_, _ = e.DeletePermissionForUser("bob", "read")
testEnforceWithoutUsers(t, e, "alice", "read", false)
testEnforceWithoutUsers(t, e, "alice", "write", false)
testEnforceWithoutUsers(t, e, "bob", "read", false)
testEnforceWithoutUsers(t, e, "bob", "write", true)
_, _ = e.DeletePermissionsForUser("bob")
testEnforceWithoutUsers(t, e, "alice", "read", false)
testEnforceWithoutUsers(t, e, "alice", "write", false)
testEnforceWithoutUsers(t, e, "bob", "read", false)
testEnforceWithoutUsers(t, e, "bob", "write", false)
e, _ = NewEnforcer("examples/rbac_with_multiple_policy_model.conf", "examples/rbac_with_multiple_policy_policy.csv")
testGetNamedPermissionsForUser(t, e, "p", "user", [][]string{{"user", "/data", "GET"}})
testGetNamedPermissionsForUser(t, e, "p2", "user", [][]string{{"user", "view"}})
}
func testGetImplicitRoles(t *testing.T, e *Enforcer, name string, res []string) {
t.Helper()
myRes, _ := e.GetImplicitRolesForUser(name)
t.Log("Implicit roles for ", name, ": ", myRes)
if !util.SetEquals(res, myRes) {
t.Error("Implicit roles for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func testGetImplicitRolesInDomain(t *testing.T, e *Enforcer, name string, domain string, res []string) {
t.Helper()
myRes, _ := e.GetImplicitRolesForUser(name, domain)
t.Log("Implicit roles in domain ", domain, " for ", name, ": ", myRes)
if !util.SetEquals(res, myRes) {
t.Error("Implicit roles in domain ", domain, " for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func TestImplicitRoleAPI(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_with_hierarchy_policy.csv")
testGetPermissions(t, e, "alice", [][]string{{"alice", "data1", "read"}})
testGetPermissions(t, e, "bob", [][]string{{"bob", "data2", "write"}})
testGetImplicitRoles(t, e, "alice", []string{"admin", "data1_admin", "data2_admin"})
testGetImplicitRoles(t, e, "bob", []string{})
e, _ = NewEnforcer("examples/rbac_with_pattern_model.conf", "examples/rbac_with_pattern_policy.csv")
e.GetRoleManager().AddMatchingFunc("matcher", util.KeyMatch)
e.AddNamedMatchingFunc("g2", "matcher", util.KeyMatch)
// testGetImplicitRoles(t, e, "cathy", []string{"/book/1/2/3/4/5", "pen_admin", "/book/*", "book_group"})
testGetImplicitRoles(t, e, "cathy", []string{"/book/1/2/3/4/5", "pen_admin"})
testGetRoles(t, e, []string{"/book/1/2/3/4/5", "pen_admin"}, "cathy")
}
func testGetImplicitPermissions(t *testing.T, e *Enforcer, name string, res [][]string, domain ...string) {
t.Helper()
myRes, _ := e.GetImplicitPermissionsForUser(name, domain...)
t.Log("Implicit permissions for ", name, ": ", myRes)
if !util.Set2DEquals(res, myRes) {
t.Error("Implicit permissions for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func testGetImplicitPermissionsWithDomain(t *testing.T, e *Enforcer, name string, domain string, res [][]string) {
t.Helper()
myRes, _ := e.GetImplicitPermissionsForUser(name, domain)
t.Log("Implicit permissions for", name, "under", domain, ":", myRes)
if !util.Set2DEquals(res, myRes) {
t.Error("Implicit permissions for", name, "under", domain, ":", myRes, ", supposed to be ", res)
}
}
func testGetNamedImplicitPermissions(t *testing.T, e *Enforcer, ptype string, gtype string, name string, res [][]string) {
t.Helper()
myRes, _ := e.GetNamedImplicitPermissionsForUser(ptype, gtype, name)
t.Log("Named implicit permissions for ", name, ": ", myRes)
if !util.Set2DEquals(res, myRes) {
t.Error("Named implicit permissions for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func TestImplicitPermissionAPI(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_with_hierarchy_policy.csv")
testGetPermissions(t, e, "alice", [][]string{{"alice", "data1", "read"}})
testGetPermissions(t, e, "bob", [][]string{{"bob", "data2", "write"}})
testGetImplicitPermissions(t, e, "alice", [][]string{{"alice", "data1", "read"}, {"data1_admin", "data1", "read"}, {"data1_admin", "data1", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})
testGetImplicitPermissions(t, e, "bob", [][]string{{"bob", "data2", "write"}})
e, _ = NewEnforcer("examples/rbac_with_domain_pattern_model.conf", "examples/rbac_with_domain_pattern_policy.csv")
e.AddNamedDomainMatchingFunc("g", "KeyMatch", util.KeyMatch)
testGetImplicitPermissions(t, e, "admin", [][]string{{"admin", "domain1", "data1", "read"}, {"admin", "domain1", "data1", "write"}, {"admin", "domain1", "data3", "read"}}, "domain1")
_, err := e.GetImplicitPermissionsForUser("admin", "domain1", "domain2")
if err == nil {
t.Error("GetImplicitPermissionsForUser should not support multiple domains")
}
testGetImplicitPermissions(t, e, "alice",
[][]string{{"admin", "domain2", "data2", "read"}, {"admin", "domain2", "data2", "write"}, {"admin", "domain2", "data3", "read"}},
"domain2")
e, _ = NewEnforcer("examples/rbac_with_multiple_policy_model.conf", "examples/rbac_with_multiple_policy_policy.csv")
testGetNamedImplicitPermissions(t, e, "p", "g", "alice", [][]string{{"user", "/data", "GET"}, {"admin", "/data", "POST"}})
testGetNamedImplicitPermissions(t, e, "p2", "g", "alice", [][]string{{"user", "view"}, {"admin", "create"}})
testGetNamedImplicitPermissions(t, e, "p", "g2", "alice", [][]string{{"user", "/data", "GET"}})
testGetNamedImplicitPermissions(t, e, "p2", "g2", "alice", [][]string{{"user", "view"}})
}
func TestImplicitPermissionAPIWithDomain(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_hierarchy_with_domains_policy.csv")
testGetImplicitPermissionsWithDomain(t, e, "alice", "domain1", [][]string{{"alice", "domain1", "data2", "read"}, {"role:reader", "domain1", "data1", "read"}, {"role:writer", "domain1", "data1", "write"}})
}
func testGetImplicitUsers(t *testing.T, e *Enforcer, res []string, permission ...string) {
t.Helper()
myRes, _ := e.GetImplicitUsersForPermission(permission...)
t.Log("Implicit users for permission: ", permission, ": ", myRes)
sort.Strings(res)
sort.Strings(myRes)
if !util.ArrayEquals(res, myRes) {
t.Error("Implicit users for permission: ", permission, ": ", myRes, ", supposed to be ", res)
}
}
func TestImplicitUserAPI(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_with_hierarchy_policy.csv")
testGetImplicitUsers(t, e, []string{"alice"}, "data1", "read")
testGetImplicitUsers(t, e, []string{"alice"}, "data1", "write")
testGetImplicitUsers(t, e, []string{"alice"}, "data2", "read")
testGetImplicitUsers(t, e, []string{"alice", "bob"}, "data2", "write")
e.ClearPolicy()
_, _ = e.AddPolicy("admin", "data1", "read")
_, _ = e.AddPolicy("bob", "data1", "read")
_, _ = e.AddGroupingPolicy("alice", "admin")
testGetImplicitUsers(t, e, []string{"alice", "bob"}, "data1", "read")
}
func testGetImplicitResourcesForUser(t *testing.T, e *Enforcer, res [][]string, user string, domain ...string) {
t.Helper()
myRes, _ := e.GetImplicitResourcesForUser(user, domain...)
t.Log("Implicit resources for user: ", user, ": ", myRes)
lessFunc := func(arr [][]string) func(int, int) bool {
return func(i, j int) bool {
policy1, policy2 := arr[i], arr[j]
for k := range policy1 {
if policy1[k] == policy2[k] {
continue
}
return policy1[k] < policy2[k]
}
return true
}
}
sort.Slice(res, lessFunc(res))
sort.Slice(myRes, lessFunc(myRes))
if !util.Array2DEquals(res, myRes) {
t.Error("Implicit resources for user: ", user, ": ", myRes, ", supposed to be ", res)
}
}
func TestGetImplicitResourcesForUser(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_with_pattern_model.conf", "examples/rbac_with_pattern_policy.csv")
testGetImplicitResourcesForUser(t, e, [][]string{
{"alice", "/pen/1", "GET"},
{"alice", "/pen2/1", "GET"},
{"alice", "/book/:id", "GET"},
{"alice", "/book2/{id}", "GET"},
{"alice", "/book/*", "GET"},
{"alice", "book_group", "GET"},
}, "alice")
testGetImplicitResourcesForUser(t, e, [][]string{
{"bob", "pen_group", "GET"},
{"bob", "/pen/:id", "GET"},
{"bob", "/pen2/{id}", "GET"},
}, "bob")
testGetImplicitResourcesForUser(t, e, [][]string{
{"cathy", "pen_group", "GET"},
{"cathy", "/pen/:id", "GET"},
{"cathy", "/pen2/{id}", "GET"},
}, "cathy")
}
func TestImplicitUsersForRole(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_with_pattern_model.conf", "examples/rbac_with_pattern_policy.csv")
testGetImplicitUsersForRole(t, e, "book_admin", []string{"alice"})
testGetImplicitUsersForRole(t, e, "pen_admin", []string{"cathy", "bob"})
testGetImplicitUsersForRole(t, e, "book_group", []string{"/book/*", "/book/:id", "/book2/{id}"})
testGetImplicitUsersForRole(t, e, "pen_group", []string{"/pen/:id", "/pen2/{id}"})
}
func testGetImplicitUsersForRole(t *testing.T, e *Enforcer, name string, res []string) {
t.Helper()
myRes, _ := e.GetImplicitUsersForRole(name)
t.Log("Implicit users for ", name, ": ", myRes)
sort.Strings(res)
sort.Strings(myRes)
if !util.SetEquals(res, myRes) {
t.Error("Implicit users for ", name, ": ", myRes, ", supposed to be ", res)
}
}
func TestExplicitPriorityModify(t *testing.T) {
e, _ := NewEnforcer("examples/priority_model_explicit.conf", "examples/priority_policy_explicit.csv")
testEnforce(t, e, "bob", "data2", "write", true)
_, err := e.AddPolicy("1", "bob", "data2", "write", "deny")
if err != nil {
t.Fatalf("AddPolicy: %v", err)
}
testEnforce(t, e, "bob", "data2", "write", false)
_, err = e.DeletePermissionsForUser("bob")
if err != nil {
t.Fatalf("DeletePermissionForUser: %v", err)
}
testEnforce(t, e, "bob", "data2", "write", true)
_, err = e.DeleteRole("data2_allow_group")
if err != nil {
t.Fatalf("DeleteRole: %v", err)
}
testEnforce(t, e, "bob", "data2", "write", false)
}
func TestCustomizedFieldIndex(t *testing.T) {
e, _ := NewEnforcer("examples/priority_model_explicit_customized.conf",
"examples/priority_policy_explicit_customized.csv")
// Due to the customized priority token, the enforcer failed to handle the priority.
testEnforce(t, e, "bob", "data2", "read", true)
// set PriorityIndex and reload
e.SetFieldIndex("p", constant.PriorityIndex, 0)
err := e.LoadPolicy()
if err != nil {
t.Fatalf("LoadPolicy: %v", err)
}
testEnforce(t, e, "bob", "data2", "read", false)
testEnforce(t, e, "bob", "data2", "write", true)
_, err = e.AddPolicy("1", "data2", "write", "deny", "bob")
if err != nil {
t.Fatalf("AddPolicy: %v", err)
}
testEnforce(t, e, "bob", "data2", "write", false)
// Due to the customized subject token, the enforcer will raise an error before SetFieldIndex.
_, err = e.DeletePermissionsForUser("bob")
if err == nil {
t.Fatalf("Failed to warning SetFieldIndex")
}
e.SetFieldIndex("p", constant.SubjectIndex, 4)
_, err = e.DeletePermissionsForUser("bob")
if err != nil {
t.Fatalf("DeletePermissionForUser: %v", err)
}
testEnforce(t, e, "bob", "data2", "write", true)
_, err = e.DeleteRole("data2_allow_group")
if err != nil {
t.Fatalf("DeleteRole: %v", err)
}
testEnforce(t, e, "bob", "data2", "write", false)
}
func testGetAllowedObjectConditions(t *testing.T, e *Enforcer, user string, act string, prefix string, res []string, expectedErr error) {
myRes, actualErr := e.GetAllowedObjectConditions(user, act, prefix)
if actualErr != expectedErr {
t.Error("actual Err: ", actualErr, ", supposed to be ", expectedErr)
}
if actualErr == nil {
log.Print("Policy: ", myRes)
if !util.ArrayEquals(res, myRes) {
t.Error("Policy: ", myRes, ", supposed to be ", res)
}
}
}
func TestGetAllowedObjectConditions(t *testing.T) {
e, _ := NewEnforcer("examples/object_conditions_model.conf", "examples/object_conditions_policy.csv")
testGetAllowedObjectConditions(t, e, "alice", "read", "r.obj.", []string{"price < 25", "category_id = 2"}, nil)
testGetAllowedObjectConditions(t, e, "admin", "read", "r.obj.", []string{"category_id = 2"}, nil)
testGetAllowedObjectConditions(t, e, "bob", "write", "r.obj.", []string{"author = bob"}, nil)
// test ErrEmptyCondition
testGetAllowedObjectConditions(t, e, "alice", "write", "r.obj.", []string{}, errors.ErrEmptyCondition)
testGetAllowedObjectConditions(t, e, "bob", "read", "r.obj.", []string{}, errors.ErrEmptyCondition)
// test ErrObjCondition
// should : e.AddPolicy("alice", "r.obj.price > 50", "read")
ok, _ := e.AddPolicy("alice", "price > 50", "read")
if ok {
testGetAllowedObjectConditions(t, e, "alice", "read", "r.obj.", []string{}, errors.ErrObjCondition)
}
// test prefix
e.ClearPolicy()
err := e.GetRoleManager().DeleteLink("alice", "admin")
if err != nil {
panic(err)
}
ok, _ = e.AddPolicies([][]string{
{"alice", "r.book.price < 25", "read"},
{"admin", "r.book.category_id = 2", "read"},
{"bob", "r.book.author = bob", "write"},
})
if ok {
testGetAllowedObjectConditions(t, e, "alice", "read", "r.book.", []string{"price < 25"}, nil)
testGetAllowedObjectConditions(t, e, "admin", "read", "r.book.", []string{"category_id = 2"}, nil)
testGetAllowedObjectConditions(t, e, "bob", "write", "r.book.", []string{"author = bob"}, nil)
}
}
func testGetImplicitUsersForResource(t *testing.T, e *Enforcer, res [][]string, resource string, domain ...string) {
t.Helper()
myRes, err := e.GetImplicitUsersForResource(resource)
if err != nil {
panic(err)
}
if !util.Set2DEquals(res, myRes) {
t.Error("Implicit users for ", resource, "in domain ", domain, " : ", myRes, ", supposed to be ", res)
} else {
t.Log("Implicit users for ", resource, "in domain ", domain, " : ", myRes)
}
}
func TestGetImplicitUsersForResource(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
testGetImplicitUsersForResource(t, e, [][]string{{"alice", "data1", "read"}}, "data1")
testGetImplicitUsersForResource(t, e, [][]string{{"bob", "data2", "write"},
{"alice", "data2", "read"},
{"alice", "data2", "write"}}, "data2")
// test duplicate permissions
_, _ = e.AddGroupingPolicy("alice", "data2_admin_2")
_, _ = e.AddPolicies([][]string{{"data2_admin_2", "data2", "read"}, {"data2_admin_2", "data2", "write"}})
testGetImplicitUsersForResource(t, e, [][]string{{"bob", "data2", "write"},
{"alice", "data2", "read"},
{"alice", "data2", "write"}}, "data2")
}
func TestGetImplicitUsersForResourceWithResourceRoles(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv")
// Test data1 resource - should return users who have access through g2 relationships
data1Users, err := e.GetNamedImplicitUsersForResource("g2", "data1")
if err != nil {
t.Fatalf("GetNamedImplicitUsersForResource failed: %v", err)
}
expectedData1Users := 2 // [alice data1 read] + [alice data_group write]
if len(data1Users) != expectedData1Users {
t.Errorf("Expected %d users for data1 resource, got %d: %v", expectedData1Users, len(data1Users), data1Users)
}
// Test data2 resource - should return users who have access through g2 relationships
data2Users, err := e.GetNamedImplicitUsersForResource("g2", "data2")
if err != nil {
t.Fatalf("GetNamedImplicitUsersForResource failed: %v", err)
}
expectedData2Users := 2 // [bob data2 write] + [alice data_group write]
if len(data2Users) != expectedData2Users {
t.Errorf("Expected %d users for data2 resource, got %d: %v", expectedData2Users, len(data2Users), data2Users)
}
// Test with "g" policy type - should return users who have access through g relationships
data1UsersG, err := e.GetNamedImplicitUsersForResource("g", "data1")
if err != nil {
t.Fatalf("GetNamedImplicitUsersForResource with g failed: %v", err)
}
expectedData1UsersG := 1 // [alice data1 read] only
if len(data1UsersG) != expectedData1UsersG {
t.Errorf("Expected %d users for data1 resource with g policy, got %d: %v", expectedData1UsersG, len(data1UsersG), data1UsersG)
}
}
func testGetImplicitUsersForResourceByDomain(t *testing.T, e *Enforcer, res [][]string, resource string, domain string) {
t.Helper()
myRes, err := e.GetImplicitUsersForResourceByDomain(resource, domain)
if err != nil {
panic(err)
}
if !util.Set2DEquals(res, myRes) {
t.Error("Implicit users for ", resource, "in domain ", domain, " : ", myRes, ", supposed to be ", res)
} else {
t.Log("Implicit users for ", resource, "in domain ", domain, " : ", myRes)
}
}
func TestGetImplicitUsersForResourceByDomain(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv")
testGetImplicitUsersForResourceByDomain(t, e, [][]string{{"alice", "domain1", "data1", "read"},
{"alice", "domain1", "data1", "write"}}, "data1", "domain1")
testGetImplicitUsersForResourceByDomain(t, e, [][]string{}, "data2", "domain1")
testGetImplicitUsersForResourceByDomain(t, e, [][]string{{"bob", "domain2", "data2", "read"},
{"bob", "domain2", "data2", "write"}}, "data2", "domain2")
}
func TestConditional(t *testing.T) {
e, _ := NewEnforcer("examples/rbac_with_domains_conditional_model.conf", "examples/rbac_with_domains_conditional_policy.csv")
g, _ := e.GetNamedGroupingPolicy("g")
for _, gp := range g {
e.AddNamedDomainLinkConditionFunc("g", gp[0], gp[1], gp[2], util.TimeMatchFunc)
}
testDomainEnforce(t, e, "alice", "domain1", "service1", "/list", true)
testDomainEnforce(t, e, "bob", "domain2", "service2", "/broadcast", true)
testDomainEnforce(t, e, "jack", "domain1", "service1", "/list", false)
testGetImplicitRolesInDomain(t, e, "alice", "domain1", []string{"test1"})
testGetRolesInDomain(t, e, "alice", "domain1", []string{"test1"})
testGetUsersInDomain(t, e, "test1", "domain1", []string{"alice"})
}
func TestMaxHierarchyLevelConsistency(t *testing.T) {
// Test consistency behavior under different maxHierarchyLevel values
testCases := []struct {
maxLevel int
name string
}{
{1, "maxHierarchyLevel=1"},
{2, "maxHierarchyLevel=2"},
{3, "maxHierarchyLevel=3"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Use model files from examples
e, err := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
if err != nil {
t.Fatalf("Failed to create enforcer: %v", err)
}
// Set the maximum hierarchy level for role manager
rm := defaultrolemanager.NewRoleManager(tc.maxLevel)
e.SetRoleManager(rm)
// Add role hierarchy: level0 -> level1 -> level2 -> level3 -> level4
_, err = e.AddRoleForUser("level0", "level1")
if err != nil {
t.Fatalf("Failed to add role for user: %v", err)
}
_, err = e.AddRoleForUser("level1", "level2")
if err != nil {
t.Fatalf("Failed to add role for user: %v", err)
}
_, err = e.AddRoleForUser("level2", "level3")
if err != nil {
t.Fatalf("Failed to add role for user: %v", err)
}
_, err = e.AddRoleForUser("level3", "level4")
if err != nil {
t.Fatalf("Failed to add role for user: %v", err)
}
// Test HasLink method
t.Run("HasLink", func(t *testing.T) {
for i := 1; i <= 4; i++ {
hasLink, err := rm.HasLink("level0", fmt.Sprintf("level%d", i))
if err != nil {
t.Fatalf("HasLink error: %v", err)
}
expected := i <= tc.maxLevel
if hasLink != expected {
t.Errorf("HasLink(level0, level%d): got %v, want %v", i, hasLink, expected)
}
}
})
// Test GetImplicitRolesForUser method
t.Run("GetImplicitRolesForUser", func(t *testing.T) {
implicitRoles, err := e.GetImplicitRolesForUser("level0")
if err != nil {
t.Fatalf("GetImplicitRolesForUser error: %v", err)
}
expectedCount := tc.maxLevel
if len(implicitRoles) != expectedCount {
t.Errorf("GetImplicitRolesForUser(level0): got %d roles %v, want %d roles",
len(implicitRoles), implicitRoles, expectedCount)
}
// Verify that returned roles are correct
for i := 1; i <= tc.maxLevel; i++ {
expectedRole := fmt.Sprintf("level%d", i)
found := false
for _, role := range implicitRoles {
if role == expectedRole {
found = true
break
}
}
if !found {
t.Errorf("Expected role %s not found in implicit roles: %v", expectedRole, implicitRoles)
}
}
})
// Test GetImplicitUsersForRole method
t.Run("GetImplicitUsersForRole", func(t *testing.T) {
implicitUsers, err := e.GetImplicitUsersForRole("level4")
if err != nil {
t.Fatalf("GetImplicitUsersForRole error: %v", err)
}
expectedCount := tc.maxLevel
if len(implicitUsers) != expectedCount {
t.Errorf("GetImplicitUsersForRole(level4): got %d users %v, want %d users",
len(implicitUsers), implicitUsers, expectedCount)
}
// Verify that returned users are correct (starting from level3 upward)
for i := 0; i < tc.maxLevel; i++ {
expectedUser := fmt.Sprintf("level%d", 3-i)
found := false
for _, user := range implicitUsers {
if user == expectedUser {
found = true
break
}
}
if !found {
t.Errorf("Expected user %s not found in implicit users: %v", expectedUser, implicitUsers)
}
}
})
// Test implicit roles for different users
t.Run("DifferentUsersImplicitRoles", func(t *testing.T) {
for i := 0; i <= 3; i++ {
user := fmt.Sprintf("level%d", i)
implicitRoles, err := e.GetImplicitRolesForUser(user)
if err != nil {
t.Fatalf("GetImplicitRolesForUser(%s) error: %v", user, err)
}
// Verify that the number of returned roles does not exceed maxHierarchyLevel
if len(implicitRoles) > tc.maxLevel {
t.Errorf("GetImplicitRolesForUser(%s): got %d roles, should not exceed maxHierarchyLevel %d",
user, len(implicitRoles), tc.maxLevel)
}
}
})
})
}
}
func testGetImplicitObjectPatternsForUser(t *testing.T, e *Enforcer, user string, domain string, action string, res []string) {
t.Helper()
myRes, err := e.GetImplicitObjectPatternsForUser(user, domain, action)
if err != nil {
t.Error("Implicit object patterns for ", user, " under domain ", domain, " with action ", action, " could not be fetched: ", err.Error())
}
t.Log("Implicit object patterns for ", user, " under domain ", domain, " with action ", action, ": ", myRes)
if !util.SetEquals(res, myRes) {
t.Error("Implicit object patterns for ", user, " under domain ", domain, " with action ", action, ": ", myRes, ", supposed to be ", res)
}
}
func TestGetImplicitObjectPatternsForUser(t *testing.T) {
// Test with domain pattern model
e, _ := NewEnforcer("examples/rbac_with_domain_pattern_model.conf", "examples/rbac_with_domain_pattern_policy.csv")
e.AddNamedDomainMatchingFunc("g", "KeyMatch", util.KeyMatch)
// Test case 1: admin user with wildcard domain access
testGetImplicitObjectPatternsForUser(t, e, "admin", "domain1", "read", []string{"data1", "data3"})
testGetImplicitObjectPatternsForUser(t, e, "admin", "domain1", "write", []string{"data1"})
// Test case 2: alice user inheriting admin role in domain2
testGetImplicitObjectPatternsForUser(t, e, "alice", "domain2", "read", []string{"data2", "data3"})
testGetImplicitObjectPatternsForUser(t, e, "alice", "domain2", "write", []string{"data2"})
// Test case 3: bob user with specific domain access
testGetImplicitObjectPatternsForUser(t, e, "bob", "domain2", "read", []string{"data2", "data3"})
testGetImplicitObjectPatternsForUser(t, e, "bob", "domain2", "write", []string{"data2"})
// Test case 4: non-existent domain (admin has wildcard access to data3)
testGetImplicitObjectPatternsForUser(t, e, "admin", "non_existent", "read", []string{"data3"})
// Test case 5: non-existent action
testGetImplicitObjectPatternsForUser(t, e, "admin", "domain1", "non_existent", []string{})
}