| // 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{}) |
| } |