This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin.git
The following commit(s) were added to refs/heads/master by this push:
new a409ec6 fix: keep link conditions for pattern domains in
ConditionalDomainManager
a409ec6 is described below
commit a409ec6f52f2f404edf4c1fb6632232a45ff3600
Author: Yang Luo <[email protected]>
AuthorDate: Tue Oct 20 21:46:51 2026 +0800
fix: keep link conditions for pattern domains in ConditionalDomainManager
---
rbac/default-role-manager/role_manager.go | 71 +++++++++++++++++++++++++-
rbac/default-role-manager/role_manager_test.go | 51 ++++++++++++++++++
2 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/rbac/default-role-manager/role_manager.go
b/rbac/default-role-manager/role_manager.go
index 2e35d57..5a8f15d 100644
--- a/rbac/default-role-manager/role_manager.go
+++ b/rbac/default-role-manager/role_manager.go
@@ -154,6 +154,21 @@ func (r *Role) getLinkConditionFunc(role *Role, domain
string) (rbac.LinkConditi
return fn.(rbac.LinkConditionFunc), ok
}
+func (r *Role) copyLinkConditions(other *Role, roleName string) {
+ other.linkConditionFuncMap.Range(func(key, value interface{}) bool {
+ if roleName == "" || key.(linkConditionFuncKey).roleName ==
roleName {
+ r.linkConditionFuncMap.Store(key, value)
+ }
+ return true
+ })
+ other.linkConditionFuncParamsMap.Range(func(key, value interface{})
bool {
+ if roleName == "" || key.(linkConditionFuncKey).roleName ==
roleName {
+ r.linkConditionFuncParamsMap.Store(key, value)
+ }
+ return true
+ })
+}
+
func (r *Role) setLinkConditionFuncParams(role *Role, domain string, params
...string) {
r.linkConditionFuncParamsMap.Store(linkConditionFuncKey{role.name,
domain}, params)
}
@@ -760,6 +775,10 @@ type ConditionalRoleManager struct {
func (crm *ConditionalRoleManager) copyFrom(other *ConditionalRoleManager) {
other.Range(func(name1, name2 string, domain ...string) bool {
_ = crm.AddLink(name1, name2, domain...)
+ if src, ok := other.load(name1); ok {
+ dst, _ := crm.getRole(name1)
+ dst.copyLinkConditions(src, name2)
+ }
return true
})
}
@@ -850,12 +869,37 @@ func (crm *ConditionalRoleManager)
checkLinkCondition(name1, name2 string, domai
if linkConditionFunc, existLinkCondition :=
crm.GetDomainLinkConditionFunc(name1, name2, domain[0]); existLinkCondition {
params, _ := crm.GetLinkConditionFuncParams(name1,
name2, domain[0])
passLinkConditionFunc, err =
linkConditionFunc(params...)
+ } else if crm.domainMatchingFunc != nil {
+ return crm.checkPatternLinkCondition(name1, name2,
domain[0])
}
}
return passLinkConditionFunc, err
}
+// checkPatternLinkCondition checks the conditions of the links inherited from
the domain patterns matching domain.
+func (crm *ConditionalRoleManager) checkPatternLinkCondition(name1, name2,
domain string) (bool, error) {
+ passLinkConditionFunc := true
+ var err error
+
+ user, ok := crm.load(name1)
+ if !ok {
+ return passLinkConditionFunc, nil
+ }
+
+ user.linkConditionFuncMap.Range(func(key, value interface{}) bool {
+ k := key.(linkConditionFuncKey)
+ if k.roleName != name2 || k.domainName == domain ||
!crm.domainMatchingFunc(domain, k.domainName) {
+ return true
+ }
+ params, _ := crm.GetLinkConditionFuncParams(name1, name2,
k.domainName)
+ passLinkConditionFunc, err =
value.(rbac.LinkConditionFunc)(params...)
+ return err == nil && !passLinkConditionFunc
+ })
+
+ return passLinkConditionFunc, err
+}
+
func (crm *ConditionalRoleManager) GetRoles(name string, domains ...string)
([]string, error) {
user, created := crm.getRole(name)
if created {
@@ -1091,6 +1135,18 @@ func (cdm *ConditionalDomainManager) load(name
interface{}) (value *ConditionalR
return nil, false
}
+func (cdm *ConditionalDomainManager)
rangeAffectedConditionalRoleManagers(domain string, fn func(rm
*ConditionalRoleManager)) {
+ if cdm.domainMatchingFunc != nil {
+ cdm.rmMap.Range(func(key, value interface{}) bool {
+ domain2 := key.(string)
+ if domain != domain2 && cdm.Match(domain2, domain) {
+ fn(value.(*ConditionalRoleManager))
+ }
+ return true
+ })
+ }
+}
+
// load or create a ConditionalRoleManager instance of domain.
func (cdm *ConditionalDomainManager) getConditionalRoleManager(domain string,
store bool) *ConditionalRoleManager {
var rm *ConditionalRoleManager
@@ -1098,6 +1154,7 @@ func (cdm *ConditionalDomainManager)
getConditionalRoleManager(domain string, st
if rm, ok = cdm.load(domain); !ok {
rm =
newConditionalRoleManagerWithMatchingFunc(cdm.maxHierarchyLevel,
cdm.matchingFunc)
+ rm.domainMatchingFunc = cdm.domainMatchingFunc
if store {
cdm.rmMap.Store(domain, rm)
}
@@ -1171,7 +1228,7 @@ func (cdm *ConditionalDomainManager) AddLink(name1
string, name2 string, domains
conditionalRoleManager := cdm.getConditionalRoleManager(domain, true)
// create role manager if it does not exist
_ = conditionalRoleManager.AddLink(name1, name2, domain)
- cdm.rangeAffectedRoleManagers(domain, func(rm *RoleManagerImpl) {
+ cdm.rangeAffectedConditionalRoleManagers(domain, func(rm
*ConditionalRoleManager) {
_ = rm.AddLink(name1, name2, domain)
})
return nil
@@ -1187,7 +1244,7 @@ func (cdm *ConditionalDomainManager) DeleteLink(name1
string, name2 string, doma
conditionalRoleManager := cdm.getConditionalRoleManager(domain, true)
// create role manager if it does not exist
_ = conditionalRoleManager.DeleteLink(name1, name2, domain)
- cdm.rangeAffectedRoleManagers(domain, func(rm *RoleManagerImpl) {
+ cdm.rangeAffectedConditionalRoleManagers(domain, func(rm
*ConditionalRoleManager) {
_ = rm.DeleteLink(name1, name2, domain)
})
return nil
@@ -1203,6 +1260,7 @@ func (cdm *ConditionalDomainManager)
AddLinkConditionFunc(userName, roleName str
// AddDomainLinkConditionFunc is based on userName, roleName, domain, add
LinkConditionFunc.
func (cdm *ConditionalDomainManager) AddDomainLinkConditionFunc(userName,
roleName, domain string, fn rbac.LinkConditionFunc) {
+ cdm.getConditionalRoleManager(domain, true) // create role manager if
it does not exist
cdm.rmMap.Range(func(key, value interface{}) bool {
value.(*ConditionalRoleManager).AddDomainLinkConditionFunc(userName, roleName,
domain, fn)
return true
@@ -1249,4 +1307,13 @@ func (cdm *ConditionalDomainManager) rebuild() {
})
return true
})
+ rmMap.Range(func(key, value interface{}) bool {
+ rm := cdm.getConditionalRoleManager(key.(string), true)
+ value.(*ConditionalRoleManager).allRoles.Range(func(name, src
interface{}) bool {
+ dst, _ := rm.getRole(name.(string))
+ dst.copyLinkConditions(src.(*Role), "")
+ return true
+ })
+ return true
+ })
}
diff --git a/rbac/default-role-manager/role_manager_test.go
b/rbac/default-role-manager/role_manager_test.go
index bd5e6e0..4274d25 100644
--- a/rbac/default-role-manager/role_manager_test.go
+++ b/rbac/default-role-manager/role_manager_test.go
@@ -434,3 +434,54 @@ func TestConcurrentHasLink(t *testing.T) {
inconsistencies, numGoroutines*numIterations)
}
}
+
+func TestConditionalDomainPatternLinkCondition(t *testing.T) {
+ deny := func(args ...string) (bool, error) { return false, nil }
+ allow := func(args ...string) (bool, error) { return true, nil }
+
+ rm := NewConditionalDomainManager(10)
+ rm.AddDomainMatchingFunc("keyMatch", util.KeyMatch)
+
+ _ = rm.AddLink("bob", "admin", "domain2")
+ _ = rm.AddLink("alice", "admin", "domain*")
+ rm.AddDomainLinkConditionFunc("alice", "admin", "domain*", deny)
+ _ = rm.AddLink("carol", "admin", "domain*")
+ rm.AddDomainLinkConditionFunc("carol", "admin", "domain*", allow)
+
+ for _, domain := range []string{"domain*", "domain1", "domain2"} {
+ if ok, _ := rm.HasLink("alice", "admin", domain); ok {
+ t.Errorf("alice should not have role admin in %s",
domain)
+ }
+ if ok, _ := rm.HasLink("carol", "admin", domain); !ok {
+ t.Errorf("carol should have role admin in %s", domain)
+ }
+ }
+ if ok, _ := rm.HasLink("bob", "admin", "domain2"); !ok {
+ t.Errorf("bob should have role admin in domain2")
+ }
+
+ rm.AddDomainLinkConditionFunc("dave", "admin", "domain9", deny)
+ _ = rm.AddLink("dave", "admin", "domain9")
+ if ok, _ := rm.HasLink("dave", "admin", "domain9"); ok {
+ t.Errorf("dave should not have role admin in domain9")
+ }
+
+ param := func(args ...string) (bool, error) { return len(args) == 1 &&
args[0] == "yes", nil }
+ rm = NewConditionalDomainManager(10)
+ _ = rm.AddLink("alice", "admin", "domain*")
+ rm.AddDomainLinkConditionFunc("alice", "admin", "domain*", param)
+ rm.SetDomainLinkConditionFuncParams("alice", "admin", "domain*", "no")
+ _ = rm.AddLink("carol", "admin", "domain*")
+ rm.AddDomainLinkConditionFunc("carol", "admin", "domain*", param)
+ rm.SetDomainLinkConditionFuncParams("carol", "admin", "domain*", "yes")
+ rm.AddDomainMatchingFunc("keyMatch", util.KeyMatch)
+
+ for _, domain := range []string{"domain*", "domain1"} {
+ if ok, _ := rm.HasLink("alice", "admin", domain); ok {
+ t.Errorf("alice should not have role admin in %s after
adding the domain matching function", domain)
+ }
+ if ok, _ := rm.HasLink("carol", "admin", domain); !ok {
+ t.Errorf("carol should have role admin in %s after
adding the domain matching function", domain)
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]