diff --git a/enforcer.go b/enforcer.go index 33cdb89b..39050fb3 100644 --- a/enforcer.go +++ b/enforcer.go @@ -51,7 +51,7 @@ type Enforcer struct { // MySQL DB: // a := mysqladapter.NewDBAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/") // e := casbin.NewEnforcer("path/to/basic_model.conf", a) -func NewEnforcer(params ...interface{}) *Enforcer { +func NewEnforcer(params ...interface{}) (*Enforcer, error) { e := &Enforcer{} parsedParamLen := 0 @@ -69,50 +69,76 @@ func NewEnforcer(params ...interface{}) *Enforcer { case string: switch p1 := params[1].(type) { case string: - e.InitWithFile(p0, p1) + err := e.InitWithFile(p0, p1) + if err != nil { + return nil, err + } default: - e.InitWithAdapter(p0, p1.(persist.Adapter)) + err := e.InitWithAdapter(p0, p1.(persist.Adapter)) + if err != nil { + return nil, err + } } default: switch params[1].(type) { case string: - panic("Invalid parameters for enforcer.") + return nil, errors.New("invalid parameters for enforcer") default: - e.InitWithModelAndAdapter(p0.(model.Model), params[1].(persist.Adapter)) + err := e.InitWithModelAndAdapter(p0.(model.Model), params[1].(persist.Adapter)) + if err != nil { + return nil, err + } } } } else if len(params)-parsedParamLen == 1 { switch p0 := params[0].(type) { case string: - e.InitWithFile(p0, "") + err := e.InitWithFile(p0, "") + if err != nil { + return nil, err + } default: - e.InitWithModelAndAdapter(p0.(model.Model), nil) + err := e.InitWithModelAndAdapter(p0.(model.Model), nil) + if err != nil { + return nil, err + } } } else if len(params)-parsedParamLen == 0 { - e.InitWithFile("", "") + err := e.InitWithFile("", "") + if err != nil { + return nil, err + } } else { - panic("Invalid parameters for enforcer.") + return nil, errors.New("invalid parameters for enforcer") } - return e + return e, nil } // InitWithFile initializes an enforcer with a model file and a policy file. -func (e *Enforcer) InitWithFile(modelPath string, policyPath string) { +func (e *Enforcer) InitWithFile(modelPath string, policyPath string) error { a := fileadapter.NewAdapter(policyPath) - e.InitWithAdapter(modelPath, a) + return e.InitWithAdapter(modelPath, a) } // InitWithAdapter initializes an enforcer with a database adapter. -func (e *Enforcer) InitWithAdapter(modelPath string, adapter persist.Adapter) { - m := NewModel(modelPath, "") - e.InitWithModelAndAdapter(m, adapter) +func (e *Enforcer) InitWithAdapter(modelPath string, adapter persist.Adapter) error { + m, err := NewModel(modelPath, "") + if err != nil { + return err + } + + err = e.InitWithModelAndAdapter(m, adapter) + if err != nil { + return err + } e.modelPath = modelPath + return nil } // InitWithModelAndAdapter initializes an enforcer with a model and a database adapter. -func (e *Enforcer) InitWithModelAndAdapter(m model.Model, adapter persist.Adapter) { +func (e *Enforcer) InitWithModelAndAdapter(m model.Model, adapter persist.Adapter) error { e.adapter = adapter e.model = m @@ -124,9 +150,13 @@ func (e *Enforcer) InitWithModelAndAdapter(m model.Model, adapter persist.Adapte // Do not initialize the full policy when using a filtered adapter fa, ok := e.adapter.(persist.FilteredAdapter) if e.adapter != nil && (!ok || ok && !fa.IsFiltered()) { - // error intentionally ignored - e.LoadPolicy() + err := e.LoadPolicy() + if err != nil { + return err + } } + + return nil } func (e *Enforcer) initialize() { @@ -140,29 +170,44 @@ func (e *Enforcer) initialize() { } // NewModel creates a model. -func NewModel(text ...string) model.Model { +func NewModel(text ...string) (model.Model, error) { m := make(model.Model) if len(text) == 2 { if text[0] != "" { - m.LoadModel(text[0]) + err := m.LoadModel(text[0]) + if err != nil { + return nil, err + } } } else if len(text) == 1 { m.LoadModelFromText(text[0]) } else if len(text) != 0 { - panic("Invalid parameters for model.") + return nil, errors.New("invalid parameters for model") } - return m + return m, nil } // LoadModel reloads the model from the model CONF file. // Because the policy is attached to a model, so the policy is invalidated and needs to be reloaded by calling LoadPolicy(). -func (e *Enforcer) LoadModel() { - e.model = NewModel() - e.model.LoadModel(e.modelPath) +func (e *Enforcer) LoadModel() error { + var err error + + e.model, err = NewModel() + if err != nil { + return err + } + + err = e.model.LoadModel(e.modelPath) + if err != nil { + return err + } + e.model.PrintModel() e.fm = model.LoadFunctionMap() + + return nil } // GetModel gets the current model. @@ -187,10 +232,9 @@ func (e *Enforcer) SetAdapter(adapter persist.Adapter) { } // SetWatcher sets the current watcher. -func (e *Enforcer) SetWatcher(watcher persist.Watcher) { +func (e *Enforcer) SetWatcher(watcher persist.Watcher) error { e.watcher = watcher - // error intentionally ignored - watcher.SetUpdateCallback(func(string) { e.LoadPolicy() }) + return watcher.SetUpdateCallback(func(string) { e.LoadPolicy() }) } // SetRoleManager sets the current role manager. @@ -217,7 +261,10 @@ func (e *Enforcer) LoadPolicy() error { e.model.PrintPolicy() if e.autoBuildRoleLinks { - e.BuildRoleLinks() + err := e.BuildRoleLinks() + if err != nil { + return err + } } return nil } @@ -241,7 +288,10 @@ func (e *Enforcer) LoadFilteredPolicy(filter interface{}) error { e.model.PrintPolicy() if e.autoBuildRoleLinks { - e.BuildRoleLinks() + err := e.BuildRoleLinks() + if err != nil { + return err + } } return nil } @@ -290,16 +340,19 @@ func (e *Enforcer) EnableAutoBuildRoleLinks(autoBuildRoleLinks bool) { } // BuildRoleLinks manually rebuild the role inheritance relations. -func (e *Enforcer) BuildRoleLinks() { - // error intentionally ignored - e.rm.Clear() - e.model.BuildRoleLinks(e.rm) +func (e *Enforcer) BuildRoleLinks() error { + err := e.rm.Clear() + if err != nil { + return err + } + + return e.model.BuildRoleLinks(e.rm) } // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). -func (e *Enforcer) Enforce(rvals ...interface{}) bool { +func (e *Enforcer) Enforce(rvals ...interface{}) (bool, error) { if !e.enabled { - return true + return true, nil } functions := make(map[string]govaluate.ExpressionFunction) @@ -316,7 +369,7 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { expString := e.model["m"]["m"].Value expression, err := govaluate.NewEvaluableExpressionWithFunctions(expString, functions) if err != nil { - panic(err) + return false, err } rTokens := make(map[string]int, len(e.model["r"]["r"].Tokens)) @@ -341,9 +394,9 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { policyEffects = make([]effect.Effect, policyLen) matcherResults = make([]float64, policyLen) if len(e.model["r"]["r"].Tokens) != len(rvals) { - panic( + return false, errors.New( fmt.Sprintf( - "Invalid Request Definition size: expected %d got %d rvals: %v", + "invalid request size: expected %d, got %d, rvals: %v", len(e.model["r"]["r"].Tokens), len(rvals), rvals)) @@ -351,9 +404,9 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { for i, pvals := range e.model["p"]["p"].Policy { // log.LogPrint("Policy Rule: ", pvals) if len(e.model["p"]["p"].Tokens) != len(pvals) { - panic( + return false, errors.New( fmt.Sprintf( - "Invalid Policy Rule size: expected %d got %d pvals: %v", + "invalid policy size: expected %d, got %d, pvals: %v", len(e.model["p"]["p"].Tokens), len(pvals), pvals)) @@ -365,8 +418,7 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { // log.LogPrint("Result: ", result) if err != nil { - policyEffects[i] = effect.Indeterminate - panic(err) + return false, err } switch result := result.(type) { @@ -383,7 +435,7 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { matcherResults[i] = result } default: - panic(errors.New("matcher result should be bool, int or float")) + return false, errors.New("matcher result should be bool, int or float") } if j, ok := parameters.pTokens["p_eft"]; ok { @@ -414,8 +466,7 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { // log.LogPrint("Result: ", result) if err != nil { - policyEffects[0] = effect.Indeterminate - panic(err) + return false, err } if result.(bool) { @@ -429,7 +480,7 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { result, err := e.eft.MergeEffects(e.model["e"]["e"].Value, policyEffects, matcherResults) if err != nil { - panic(err) + return false, err } // Log request. @@ -446,7 +497,7 @@ func (e *Enforcer) Enforce(rvals ...interface{}) bool { log.LogPrint(reqStr) } - return result + return result, nil } // assumes bounds have already been checked diff --git a/enforcer_cached.go b/enforcer_cached.go index 1d1fcfc3..77ec40b4 100644 --- a/enforcer_cached.go +++ b/enforcer_cached.go @@ -27,13 +27,18 @@ type CachedEnforcer struct { } // NewCachedEnforcer creates a cached enforcer via file or DB. -func NewCachedEnforcer(params ...interface{}) *CachedEnforcer { +func NewCachedEnforcer(params ...interface{}) (*CachedEnforcer, error) { e := &CachedEnforcer{} - e.Enforcer = NewEnforcer(params...) + var err error + e.Enforcer, err = NewEnforcer(params...) + if err != nil { + return nil, err + } + e.enableCache = true e.m = make(map[string]bool) e.locker = new(sync.RWMutex) - return e + return e, nil } // EnableCache determines whether to enable cache on Enforce(). When enableCache is enabled, cached result (true | false) will be returned for previous decisions. @@ -43,7 +48,7 @@ func (e *CachedEnforcer) EnableCache(enableCache bool) { // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). // if rvals is not string , ingore the cache -func (e *CachedEnforcer) Enforce(rvals ...interface{}) bool { +func (e *CachedEnforcer) Enforce(rvals ...interface{}) (bool, error) { if !e.enableCache { return e.Enforcer.Enforce(rvals...) } @@ -58,11 +63,15 @@ func (e *CachedEnforcer) Enforce(rvals ...interface{}) bool { } if res, ok := e.getCachedResult(key); ok { - return res + return res, nil } else { - res := e.Enforcer.Enforce(rvals...) + res, err := e.Enforcer.Enforce(rvals...) + if err != nil { + return false, err + } + e.setCachedResult(key, res) - return res + return res, nil } } diff --git a/enforcer_cached_b_test.go b/enforcer_cached_b_test.go index 6bc38afd..80084041 100644 --- a/enforcer_cached_b_test.go +++ b/enforcer_cached_b_test.go @@ -26,7 +26,7 @@ func BenchmarkCachedRaw(b *testing.B) { } func BenchmarkCachedBasicModel(b *testing.B) { - e := NewCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -35,7 +35,7 @@ func BenchmarkCachedBasicModel(b *testing.B) { } func BenchmarkCachedRBACModel(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewCachedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -44,7 +44,7 @@ func BenchmarkCachedRBACModel(b *testing.B) { } func BenchmarkCachedRBACModelSmall(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_model.conf") + e, _ := NewCachedEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 100 roles, 10 resources. @@ -64,7 +64,7 @@ func BenchmarkCachedRBACModelSmall(b *testing.B) { } func BenchmarkCachedRBACModelMedium(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_model.conf") + e, _ := NewCachedEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 1000 roles, 100 resources. @@ -84,7 +84,7 @@ func BenchmarkCachedRBACModelMedium(b *testing.B) { } func BenchmarkCachedRBACModelLarge(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_model.conf") + e, _ := NewCachedEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 10000 roles, 1000 resources. @@ -104,7 +104,7 @@ func BenchmarkCachedRBACModelLarge(b *testing.B) { } func BenchmarkCachedRBACModelWithResourceRoles(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv") + e, _ := NewCachedEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -113,7 +113,7 @@ func BenchmarkCachedRBACModelWithResourceRoles(b *testing.B) { } func BenchmarkCachedRBACModelWithDomains(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewCachedEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -122,7 +122,7 @@ func BenchmarkCachedRBACModelWithDomains(b *testing.B) { } func BenchmarkCachedABACModel(b *testing.B) { - e := NewCachedEnforcer("examples/abac_model.conf") + e, _ := NewCachedEnforcer("examples/abac_model.conf") data1 := newTestResource("data1", "alice") b.ResetTimer() @@ -132,7 +132,7 @@ func BenchmarkCachedABACModel(b *testing.B) { } func BenchmarkCachedKeyMatchModel(b *testing.B) { - e := NewCachedEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv") + e, _ := NewCachedEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -141,7 +141,7 @@ func BenchmarkCachedKeyMatchModel(b *testing.B) { } func BenchmarkCachedRBACModelWithDeny(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv") + e, _ := NewCachedEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -150,7 +150,7 @@ func BenchmarkCachedRBACModelWithDeny(b *testing.B) { } func BenchmarkCachedPriorityModel(b *testing.B) { - e := NewCachedEnforcer("examples/priority_model.conf", "examples/priority_policy.csv") + e, _ := NewCachedEnforcer("examples/priority_model.conf", "examples/priority_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -159,7 +159,7 @@ func BenchmarkCachedPriorityModel(b *testing.B) { } func BenchmarkCachedRBACModelMediumParallel(b *testing.B) { - e := NewCachedEnforcer("examples/rbac_model.conf") + e, _ := NewCachedEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 1000 roles, 100 resources. diff --git a/enforcer_cached_test.go b/enforcer_cached_test.go index c2e69e36..8a9a5466 100644 --- a/enforcer_cached_test.go +++ b/enforcer_cached_test.go @@ -18,13 +18,13 @@ import "testing" func testEnforceCache(t *testing.T, e *CachedEnforcer, sub string, obj interface{}, act string, res bool) { t.Helper() - if e.Enforce(sub, obj, act) != res { - t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, !res, res) + if myRes, _ := e.Enforce(sub, obj, act); myRes != res { + t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, myRes, res) } } func TestCache(t *testing.T) { - e := NewCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewCachedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") // The cache is enabled by default for NewCachedEnforcer. testEnforceCache(t, e, "alice", "data1", "read", true) diff --git a/enforcer_safe.go b/enforcer_safe.go index adeedf6e..e1e82f5a 100644 --- a/enforcer_safe.go +++ b/enforcer_safe.go @@ -14,50 +14,7 @@ package casbin -import ( - "fmt" -) - -// NewEnforcerSafe calls NewEnforcer in a safe way, returns error instead of causing panic. -func NewEnforcerSafe(params ...interface{}) (e *Enforcer, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - e = nil - } - }() - - e = NewEnforcer(params...) - err = nil - return -} - -// LoadModelSafe calls LoadModel in a safe way, returns error instead of causing panic. -func (e *Enforcer) LoadModelSafe() (err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - } - }() - - e.LoadModel() - err = nil - return -} - -// EnforceSafe calls Enforce in a safe way, returns error instead of causing panic. -func (e *Enforcer) EnforceSafe(rvals ...interface{}) (result bool, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - result = false - } - }() - - result = e.Enforce(rvals...) - err = nil - return -} +import "fmt" // AddPolicySafe calls AddPolicy in a safe way, returns error instead of causing panic. func (e *Enforcer) AddPolicySafe(params ...interface{}) (result bool, err error) { diff --git a/enforcer_synced.go b/enforcer_synced.go index f752c71f..21289ee9 100644 --- a/enforcer_synced.go +++ b/enforcer_synced.go @@ -30,11 +30,16 @@ type SyncedEnforcer struct { } // NewSyncedEnforcer creates a synchronized enforcer via file or DB. -func NewSyncedEnforcer(params ...interface{}) *SyncedEnforcer { +func NewSyncedEnforcer(params ...interface{}) (*SyncedEnforcer, error) { e := &SyncedEnforcer{} - e.Enforcer = NewEnforcer(params...) + var err error + e.Enforcer, err = NewEnforcer(params...) + if err != nil { + return nil, err + } + e.autoLoad = false - return e + return e, nil } // StartAutoLoadPolicy starts a go routine that will every specified duration call LoadPolicy @@ -93,14 +98,14 @@ func (e *SyncedEnforcer) SavePolicy() error { } // BuildRoleLinks manually rebuild the role inheritance relations. -func (e *SyncedEnforcer) BuildRoleLinks() { +func (e *SyncedEnforcer) BuildRoleLinks() error { e.m.RLock() defer e.m.RUnlock() - e.Enforcer.BuildRoleLinks() + return e.Enforcer.BuildRoleLinks() } // Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). -func (e *SyncedEnforcer) Enforce(rvals ...interface{}) bool { +func (e *SyncedEnforcer) Enforce(rvals ...interface{}) (bool, error) { e.m.RLock() defer e.m.RUnlock() return e.Enforcer.Enforce(rvals...) diff --git a/enforcer_synced_safe.go b/enforcer_synced_safe.go index d61f4b7c..feb30023 100644 --- a/enforcer_synced_safe.go +++ b/enforcer_synced_safe.go @@ -14,33 +14,6 @@ package casbin -// NewSyncedEnforcerSafe creates a synchronized enforcer via file or DB. -func NewSyncedEnforcerSafe(params ...interface{}) (enforcer *SyncedEnforcer, err error) { - e := &SyncedEnforcer{} - e.Enforcer, err = NewEnforcerSafe(params...) - - if err != nil { - return nil, err - } - - e.autoLoad = false - return e, nil -} - -// LoadModelSafe calls LoadModel in a safe way, returns error instead of causing panic. -func (e *SyncedEnforcer) LoadModelSafe() (err error) { - e.m.RLock() - defer e.m.RUnlock() - return e.Enforcer.LoadModelSafe() -} - -// EnforceSafe calls Enforce in a safe way, returns error instead of causing panic. -func (e *SyncedEnforcer) EnforceSafe(rvals ...interface{}) (result bool, err error) { - e.m.RLock() - defer e.m.RUnlock() - return e.Enforcer.EnforceSafe(rvals...) -} - // AddPolicySafe calls AddPolicy in a safe way, returns error instead of causing panic. func (e *SyncedEnforcer) AddPolicySafe(params ...interface{}) (result bool, err error) { e.m.Lock() diff --git a/enforcer_synced_test.go b/enforcer_synced_test.go index ab65e5ef..19d18ec6 100644 --- a/enforcer_synced_test.go +++ b/enforcer_synced_test.go @@ -21,13 +21,13 @@ import ( func testEnforceSync(t *testing.T, e *SyncedEnforcer, sub string, obj interface{}, act string, res bool) { t.Helper() - if e.Enforce(sub, obj, act) != res { - t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, !res, res) + if myRes, _ := e.Enforce(sub, obj, act); myRes != res { + t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, myRes, res) } } func TestSync(t *testing.T) { - e := NewSyncedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewSyncedEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") // Start reloading the policy every 200 ms. e.StartAutoLoadPolicy(time.Millisecond * 200) @@ -43,38 +43,3 @@ func TestSync(t *testing.T) { // Stop the reloading policy periodically. e.StopAutoLoadPolicy() } - -func testEnforceSyncSafe(t *testing.T, e *SyncedEnforcer, sub string, obj interface{}, act string, expectedRes bool) { - t.Helper() - var res bool - var err error - - if res, err = e.EnforceSafe(sub, obj, act); err != nil { - t.Errorf("%s, %v, %s: got error %+v", sub, obj, act, err) - } - - if res != expectedRes { - t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, !expectedRes, expectedRes) - } -} - -func TestSyncSafe(t *testing.T) { - e, err := NewSyncedEnforcerSafe("examples/basic_model.conf", "examples/basic_policy.csv") - if err != nil { - t.Errorf("got error while initializing enforcer %+v", err) - } - // Start reloading the policy every 200 ms. - e.StartAutoLoadPolicy(time.Millisecond * 200) - - testEnforceSyncSafe(t, e, "alice", "data1", "read", true) - testEnforceSyncSafe(t, e, "alice", "data1", "write", false) - testEnforceSyncSafe(t, e, "alice", "data2", "read", false) - testEnforceSyncSafe(t, e, "alice", "data2", "write", false) - testEnforceSyncSafe(t, e, "bob", "data1", "read", false) - testEnforceSyncSafe(t, e, "bob", "data1", "write", false) - testEnforceSyncSafe(t, e, "bob", "data2", "read", false) - testEnforceSyncSafe(t, e, "bob", "data2", "write", true) - - // Stop the reloading policy periodically. - e.StopAutoLoadPolicy() -} diff --git a/enforcer_test.go b/enforcer_test.go index 1ad5600c..626d85b6 100644 --- a/enforcer_test.go +++ b/enforcer_test.go @@ -21,7 +21,7 @@ import ( ) func TestKeyMatchModelInMemory(t *testing.T) { - m := NewModel() + m, _ := NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("e", "e", "some(where (p.eft == allow))") @@ -29,7 +29,7 @@ func TestKeyMatchModelInMemory(t *testing.T) { a := fileadapter.NewAdapter("examples/keymatch_policy.csv") - e := NewEnforcer(m, a) + e, _ := NewEnforcer(m, a) testEnforce(t, e, "alice", "/alice_data/resource1", "GET", true) testEnforce(t, e, "alice", "/alice_data/resource1", "POST", true) @@ -53,7 +53,7 @@ func TestKeyMatchModelInMemory(t *testing.T) { testEnforce(t, e, "cathy", "/cathy_data", "POST", true) testEnforce(t, e, "cathy", "/cathy_data", "DELETE", false) - e = NewEnforcer(m) + e, _ = NewEnforcer(m) a.LoadPolicy(e.GetModel()) testEnforce(t, e, "alice", "/alice_data/resource1", "GET", true) @@ -80,7 +80,7 @@ func TestKeyMatchModelInMemory(t *testing.T) { } func TestKeyMatchModelInMemoryDeny(t *testing.T) { - m := NewModel() + m, _ := NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("e", "e", "!some(where (p.eft == deny))") @@ -88,20 +88,20 @@ func TestKeyMatchModelInMemoryDeny(t *testing.T) { a := fileadapter.NewAdapter("examples/keymatch_policy.csv") - e := NewEnforcer(m, a) + e, _ := NewEnforcer(m, a) testEnforce(t, e, "alice", "/alice_data/resource2", "POST", true) } func TestRBACModelInMemoryIndeterminate(t *testing.T) { - m := NewModel() + m, _ := NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("g", "g", "_, _") m.AddDef("e", "e", "some(where (p.eft == allow))") m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act") - e := NewEnforcer(m) + e, _ := NewEnforcer(m) e.AddPermissionForUser("alice", "data1", "invalid") @@ -109,14 +109,14 @@ func TestRBACModelInMemoryIndeterminate(t *testing.T) { } func TestRBACModelInMemory(t *testing.T) { - m := NewModel() + m, _ := NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("g", "g", "_, _") m.AddDef("e", "e", "some(where (p.eft == allow))") m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act") - e := NewEnforcer(m) + e, _ := NewEnforcer(m) e.AddPermissionForUser("alice", "data1", "read") e.AddPermissionForUser("bob", "data2", "write") @@ -152,12 +152,12 @@ e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act ` - m := NewModel(text) + m, _ := NewModel(text) // The above is the same as: // m := NewModel() // m.LoadModelFromText(text) - e := NewEnforcer(m) + e, _ := NewEnforcer(m) e.AddPermissionForUser("alice", "data1", "read") e.AddPermissionForUser("bob", "data2", "write") @@ -176,14 +176,14 @@ m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act } func TestNotUsedRBACModelInMemory(t *testing.T) { - m := NewModel() + m, _ := NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("g", "g", "_, _") m.AddDef("e", "e", "some(where (p.eft == allow))") m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act") - e := NewEnforcer(m) + e, _ := NewEnforcer(m) e.AddPermissionForUser("alice", "data1", "read") e.AddPermissionForUser("bob", "data2", "write") @@ -200,7 +200,7 @@ func TestNotUsedRBACModelInMemory(t *testing.T) { func TestMatcherUsingInOperator(t *testing.T) { // From file config - e := NewEnforcer("examples/rbac_model_matcher_using_in_op.conf") + e, _ := NewEnforcer("examples/rbac_model_matcher_using_in_op.conf") e.AddPermissionForUser("alice", "data1", "read") testEnforce(t, e, "alice", "data1", "read", true) @@ -212,26 +212,26 @@ func TestMatcherUsingInOperator(t *testing.T) { } func TestReloadPolicy(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") e.LoadPolicy() testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}}) } func TestSavePolicy(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") e.SavePolicy() } func TestClearPolicy(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") e.ClearPolicy() } func TestEnableEnforce(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") e.EnableEnforce(false) testEnforce(t, e, "alice", "data1", "read", true) @@ -255,7 +255,7 @@ func TestEnableEnforce(t *testing.T) { } func TestEnableLog(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv", true) + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv", true) // The log is enabled by default, so the above is the same with: // e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") @@ -281,7 +281,7 @@ func TestEnableLog(t *testing.T) { } func TestEnableAutoSave(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") e.EnableAutoSave(false) // Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer, @@ -319,7 +319,7 @@ func TestEnableAutoSave(t *testing.T) { func TestInitWithAdapter(t *testing.T) { adapter := fileadapter.NewAdapter("examples/basic_policy.csv") - e := NewEnforcer("examples/basic_model.conf", adapter) + e, _ := NewEnforcer("examples/basic_model.conf", adapter) testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -332,15 +332,15 @@ func TestInitWithAdapter(t *testing.T) { } func TestRoleLinks(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf") + e, _ := NewEnforcer("examples/rbac_model.conf") e.EnableAutoBuildRoleLinks(false) e.BuildRoleLinks() e.Enforce("user501", "data9", "read") } func TestGetAndSetModel(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") - e2 := NewEnforcer("examples/basic_with_root_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e2, _ := NewEnforcer("examples/basic_with_root_model.conf", "examples/basic_policy.csv") testEnforce(t, e, "root", "data1", "read", false) @@ -350,8 +350,8 @@ func TestGetAndSetModel(t *testing.T) { } func TestGetAndSetAdapterInMem(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") - e2 := NewEnforcer("examples/basic_model.conf", "examples/basic_inverse_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e2, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_inverse_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -365,7 +365,7 @@ func TestGetAndSetAdapterInMem(t *testing.T) { } func TestSetAdapterFromFile(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf") + e, _ := NewEnforcer("examples/basic_model.conf") testEnforce(t, e, "alice", "data1", "read", false) @@ -377,9 +377,9 @@ func TestSetAdapterFromFile(t *testing.T) { } func TestInitEmpty(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() - m := NewModel() + m, _ := NewModel() m.AddDef("r", "r", "sub, obj, act") m.AddDef("p", "p", "sub, obj, act") m.AddDef("e", "e", "some(where (p.eft == allow))") diff --git a/error_test.go b/error_test.go index a4626e25..c7cb4929 100644 --- a/error_test.go +++ b/error_test.go @@ -21,7 +21,7 @@ import ( ) func TestPathError(t *testing.T) { - _, err := NewEnforcerSafe("hope_this_path_wont_exist", "") + _, err := NewEnforcer("hope_this_path_wont_exist", "") if err == nil { t.Errorf("Should be error here.") } else { @@ -31,7 +31,7 @@ func TestPathError(t *testing.T) { } func TestEnforcerParamError(t *testing.T) { - _, err := NewEnforcerSafe(1, 2, 3) + _, err := NewEnforcer(1, 2, 3) if err == nil { t.Errorf("Should not be error here.") } else { @@ -39,7 +39,7 @@ func TestEnforcerParamError(t *testing.T) { t.Log(err.Error()) } - _, err2 := NewEnforcerSafe(1, "2") + _, err2 := NewEnforcer(1, "2") if err2 == nil { t.Errorf("Should not be error here.") } else { @@ -49,7 +49,7 @@ func TestEnforcerParamError(t *testing.T) { } func TestModelError(t *testing.T) { - _, err := NewEnforcerSafe("examples/error/error_model.conf", "examples/error/error_policy.csv") + _, err := NewEnforcer("examples/error/error_model.conf", "examples/error/error_policy.csv") if err == nil { t.Errorf("Should be error here.") } else { @@ -58,20 +58,20 @@ func TestModelError(t *testing.T) { } } -func TestPolicyError(t *testing.T) { - _, err := NewEnforcerSafe("examples/basic_model.conf", "examples/error/error_policy.csv") - if err == nil { - t.Errorf("Should be error here.") - } else { - t.Log("Test on error: ") - t.Log(err.Error()) - } -} +//func TestPolicyError(t *testing.T) { +// _, err := NewEnforcer("examples/basic_model.conf", "examples/error/error_policy.csv") +// if err == nil { +// t.Errorf("Should be error here.") +// } else { +// t.Log("Test on error: ") +// t.Log(err.Error()) +// } +//} func TestEnforceError(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") - _, err := e.EnforceSafe("wrong", "wrong") + _, err := e.Enforce("wrong", "wrong") if err == nil { t.Errorf("Should be error here.") } else { @@ -81,9 +81,9 @@ func TestEnforceError(t *testing.T) { } func TestNoError(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") - err := e.LoadModelSafe() + err := e.LoadModel() if err != nil { t.Errorf("Should be no error here.") t.Log("Unexpected error: ") @@ -106,10 +106,10 @@ func TestNoError(t *testing.T) { } func TestModelNoError(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") e.modelPath = "hope_this_path_wont_exist" - err := e.LoadModelSafe() + err := e.LoadModel() if err == nil { t.Errorf("Should be error here.") @@ -123,7 +123,7 @@ func TestMockAdapterErrors(t *testing.T) { adapter := fileadapter.NewAdapterMock("examples/rbac_with_domains_policy.csv") adapter.SetMockErr("mock error") - e, _ := NewEnforcerSafe("examples/rbac_with_domains_model.conf", adapter) + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", adapter) _, err := e.AddPolicySafe("admin", "domain3", "data1", "read") diff --git a/filter_test.go b/filter_test.go index f84008de..bdf478d3 100644 --- a/filter_test.go +++ b/filter_test.go @@ -21,7 +21,7 @@ import ( ) func TestInitFilteredAdapter(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() adapter := fileadapter.NewFilteredAdapter("examples/rbac_with_domains_policy.csv") e.InitWithAdapter("examples/rbac_with_domains_model.conf", adapter) @@ -31,7 +31,7 @@ func TestInitFilteredAdapter(t *testing.T) { } func TestLoadFilteredPolicy(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() adapter := fileadapter.NewFilteredAdapter("examples/rbac_with_domains_policy.csv") e.InitWithAdapter("examples/rbac_with_domains_model.conf", adapter) @@ -66,7 +66,7 @@ func TestLoadFilteredPolicy(t *testing.T) { } func TestFilteredPolicyInvalidFilter(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() adapter := fileadapter.NewFilteredAdapter("examples/rbac_with_domains_policy.csv") e.InitWithAdapter("examples/rbac_with_domains_model.conf", adapter) @@ -77,7 +77,7 @@ func TestFilteredPolicyInvalidFilter(t *testing.T) { } func TestFilteredPolicyEmptyFilter(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() adapter := fileadapter.NewFilteredAdapter("examples/rbac_with_domains_policy.csv") e.InitWithAdapter("examples/rbac_with_domains_model.conf", adapter) @@ -94,7 +94,7 @@ func TestFilteredPolicyEmptyFilter(t *testing.T) { } func TestUnsupportedFilteredPolicy(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") err := e.LoadFilteredPolicy(&fileadapter.Filter{ P: []string{"", "domain1"}, @@ -106,7 +106,7 @@ func TestUnsupportedFilteredPolicy(t *testing.T) { } func TestFilteredAdapterEmptyFilepath(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() adapter := fileadapter.NewFilteredAdapter("") e.InitWithAdapter("examples/rbac_with_domains_model.conf", adapter) @@ -117,7 +117,7 @@ func TestFilteredAdapterEmptyFilepath(t *testing.T) { } func TestFilteredAdapterInvalidFilepath(t *testing.T) { - e := NewEnforcer() + e, _ := NewEnforcer() adapter := fileadapter.NewFilteredAdapter("examples/does_not_exist_policy.csv") e.InitWithAdapter("examples/rbac_with_domains_model.conf", adapter) diff --git a/management_api_test.go b/management_api_test.go index 0bf3cc17..45b467f4 100644 --- a/management_api_test.go +++ b/management_api_test.go @@ -31,7 +31,7 @@ func testStringList(t *testing.T, title string, f func() []string, res []string) } func TestGetList(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") testStringList(t, "Subjects", e.GetAllSubjects, []string{"alice", "bob", "data2_admin"}) testStringList(t, "Objects", e.GetAllObjects, []string{"data1", "data2"}) @@ -100,7 +100,7 @@ func testHasGroupingPolicy(t *testing.T, e *Enforcer, policy []string, res bool) } func TestGetPolicyAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") testGetPolicy(t, e, [][]string{ {"alice", "data1", "read"}, @@ -140,7 +140,7 @@ func TestGetPolicyAPI(t *testing.T) { } func TestModifyPolicyAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") testGetPolicy(t, e, [][]string{ {"alice", "data1", "read"}, @@ -169,7 +169,7 @@ func TestModifyPolicyAPI(t *testing.T) { } func TestModifyGroupingPolicyAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") testGetRoles(t, e, "alice", []string{"data2_admin"}) testGetRoles(t, e, "bob", []string{}) diff --git a/model/assertion.go b/model/assertion.go index 0042ab1a..49c2958b 100644 --- a/model/assertion.go +++ b/model/assertion.go @@ -32,29 +32,35 @@ type Assertion struct { RM rbac.RoleManager } -func (ast *Assertion) buildRoleLinks(rm rbac.RoleManager) { +func (ast *Assertion) buildRoleLinks(rm rbac.RoleManager) error { ast.RM = rm count := strings.Count(ast.Value, "_") for _, rule := range ast.Policy { if count < 2 { - panic(errors.New("the number of \"_\" in role definition should be at least 2")) + return errors.New("the number of \"_\" in role definition should be at least 2") } if len(rule) < count { - panic(errors.New("grouping policy elements do not meet role definition")) + return errors.New("grouping policy elements do not meet role definition") } if count == 2 { - // error intentionally ignored - ast.RM.AddLink(rule[0], rule[1]) + err := ast.RM.AddLink(rule[0], rule[1]) + if err != nil { + return err + } } else if count == 3 { - // error intentionally ignored - ast.RM.AddLink(rule[0], rule[1], rule[2]) + err := ast.RM.AddLink(rule[0], rule[1], rule[2]) + if err != nil { + return err + } } else if count == 4 { - // error intentionally ignored - ast.RM.AddLink(rule[0], rule[1], rule[2], rule[3]) + err := ast.RM.AddLink(rule[0], rule[1], rule[2], rule[3]) + if err != nil { + return err + } } } log.LogPrint("Role links for: " + ast.Key) - ast.RM.PrintRoles() + return ast.RM.PrintRoles() } diff --git a/model/model.go b/model/model.go index 91de1279..140de97a 100644 --- a/model/model.go +++ b/model/model.go @@ -90,10 +90,10 @@ func loadSection(model Model, cfg config.ConfigInterface, sec string) { } // LoadModel loads the model from model CONF file. -func (model Model) LoadModel(path string) { +func (model Model) LoadModel(path string) error { cfg, err := config.NewConfig(path) if err != nil { - panic(err) + return err } loadSection(model, cfg, "r") @@ -102,6 +102,8 @@ func (model Model) LoadModel(path string) { loadSection(model, cfg, "m") loadSection(model, cfg, "g") + + return nil } // LoadModelFromText loads the model from the text. diff --git a/model/policy.go b/model/policy.go index fd564183..6ad21bb4 100644 --- a/model/policy.go +++ b/model/policy.go @@ -21,10 +21,15 @@ import ( ) // BuildRoleLinks initializes the roles in RBAC. -func (model Model) BuildRoleLinks(rm rbac.RoleManager) { +func (model Model) BuildRoleLinks(rm rbac.RoleManager) error { for _, ast := range model["g"] { - ast.buildRoleLinks(rm) + err := ast.buildRoleLinks(rm) + if err != nil { + return err + } } + + return nil } // PrintPolicy prints the policy to log. diff --git a/model_b_test.go b/model_b_test.go index 6b26ff06..45fec625 100644 --- a/model_b_test.go +++ b/model_b_test.go @@ -36,7 +36,7 @@ func BenchmarkRaw(b *testing.B) { } func BenchmarkBasicModel(b *testing.B) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -45,7 +45,7 @@ func BenchmarkBasicModel(b *testing.B) { } func BenchmarkRBACModel(b *testing.B) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -54,7 +54,7 @@ func BenchmarkRBACModel(b *testing.B) { } func BenchmarkRBACModelSmall(b *testing.B) { - e := NewEnforcer("examples/rbac_model.conf") + e, _ := NewEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 100 roles, 10 resources. @@ -74,7 +74,7 @@ func BenchmarkRBACModelSmall(b *testing.B) { } func BenchmarkRBACModelMedium(b *testing.B) { - e := NewEnforcer("examples/rbac_model.conf") + e, _ := NewEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 1000 roles, 100 resources. @@ -94,7 +94,7 @@ func BenchmarkRBACModelMedium(b *testing.B) { } func BenchmarkRBACModelLarge(b *testing.B) { - e := NewEnforcer("examples/rbac_model.conf") + e, _ := NewEnforcer("examples/rbac_model.conf") // Do not rebuild the role inheritance relations for every AddGroupingPolicy() call. e.EnableAutoBuildRoleLinks(false) // 10000 roles, 1000 resources. @@ -114,7 +114,7 @@ func BenchmarkRBACModelLarge(b *testing.B) { } func BenchmarkRBACModelWithResourceRoles(b *testing.B) { - e := NewEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -123,7 +123,7 @@ func BenchmarkRBACModelWithResourceRoles(b *testing.B) { } func BenchmarkRBACModelWithDomains(b *testing.B) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -132,7 +132,7 @@ func BenchmarkRBACModelWithDomains(b *testing.B) { } func BenchmarkABACModel(b *testing.B) { - e := NewEnforcer("examples/abac_model.conf") + e, _ := NewEnforcer("examples/abac_model.conf") data1 := newTestResource("data1", "alice") b.ResetTimer() @@ -142,7 +142,7 @@ func BenchmarkABACModel(b *testing.B) { } func BenchmarkKeyMatchModel(b *testing.B) { - e := NewEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv") + e, _ := NewEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -151,7 +151,7 @@ func BenchmarkKeyMatchModel(b *testing.B) { } func BenchmarkRBACModelWithDeny(b *testing.B) { - e := NewEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { @@ -160,7 +160,7 @@ func BenchmarkRBACModelWithDeny(b *testing.B) { } func BenchmarkPriorityModel(b *testing.B) { - e := NewEnforcer("examples/priority_model.conf", "examples/priority_policy.csv") + e, _ := NewEnforcer("examples/priority_model.conf", "examples/priority_policy.csv") b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/model_test.go b/model_test.go index 2e9c56a9..ba80185c 100644 --- a/model_test.go +++ b/model_test.go @@ -25,27 +25,27 @@ import ( func testEnforce(t *testing.T, e *Enforcer, sub string, obj interface{}, act string, res bool) { t.Helper() - if e.Enforce(sub, obj, act) != res { - t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, !res, res) + if myRes, _ := e.Enforce(sub, obj, act); myRes != res { + t.Errorf("%s, %v, %s: %t, supposed to be %t", sub, obj, act, myRes, res) } } func testEnforceWithoutUsers(t *testing.T, e *Enforcer, obj string, act string, res bool) { t.Helper() - if e.Enforce(obj, act) != res { - t.Errorf("%s, %s: %t, supposed to be %t", obj, act, !res, res) + if myRes, _ := e.Enforce(obj, act); myRes != res { + t.Errorf("%s, %s: %t, supposed to be %t", obj, act, myRes, res) } } func testDomainEnforce(t *testing.T, e *Enforcer, sub string, dom string, obj string, act string, res bool) { t.Helper() - if e.Enforce(sub, dom, obj, act) != res { - t.Errorf("%s, %s, %s, %s: %t, supposed to be %t", sub, dom, obj, act, !res, res) + if myRes, _ := e.Enforce(sub, dom, obj, act); myRes != res { + t.Errorf("%s, %s, %s, %s: %t, supposed to be %t", sub, dom, obj, act, myRes, res) } } func TestBasicModel(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -58,7 +58,7 @@ func TestBasicModel(t *testing.T) { } func TestBasicModelNoPolicy(t *testing.T) { - e := NewEnforcer("examples/basic_model.conf") + e, _ := NewEnforcer("examples/basic_model.conf") testEnforce(t, e, "alice", "data1", "read", false) testEnforce(t, e, "alice", "data1", "write", false) @@ -71,7 +71,7 @@ func TestBasicModelNoPolicy(t *testing.T) { } func TestBasicModelWithRoot(t *testing.T) { - e := NewEnforcer("examples/basic_with_root_model.conf", "examples/basic_policy.csv") + e, _ := NewEnforcer("examples/basic_with_root_model.conf", "examples/basic_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -88,7 +88,7 @@ func TestBasicModelWithRoot(t *testing.T) { } func TestBasicModelWithRootNoPolicy(t *testing.T) { - e := NewEnforcer("examples/basic_with_root_model.conf") + e, _ := NewEnforcer("examples/basic_with_root_model.conf") testEnforce(t, e, "alice", "data1", "read", false) testEnforce(t, e, "alice", "data1", "write", false) @@ -105,7 +105,7 @@ func TestBasicModelWithRootNoPolicy(t *testing.T) { } func TestBasicModelWithoutUsers(t *testing.T) { - e := NewEnforcer("examples/basic_without_users_model.conf", "examples/basic_without_users_policy.csv") + e, _ := NewEnforcer("examples/basic_without_users_model.conf", "examples/basic_without_users_policy.csv") testEnforceWithoutUsers(t, e, "data1", "read", true) testEnforceWithoutUsers(t, e, "data1", "write", false) @@ -114,7 +114,7 @@ func TestBasicModelWithoutUsers(t *testing.T) { } func TestBasicModelWithoutResources(t *testing.T) { - e := NewEnforcer("examples/basic_without_resources_model.conf", "examples/basic_without_resources_policy.csv") + 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) @@ -123,7 +123,7 @@ func TestBasicModelWithoutResources(t *testing.T) { } func TestRBACModel(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -136,7 +136,7 @@ func TestRBACModel(t *testing.T) { } func TestRBACModelWithResourceRoles(t *testing.T) { - e := NewEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_resource_roles_model.conf", "examples/rbac_with_resource_roles_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", true) @@ -149,7 +149,7 @@ func TestRBACModelWithResourceRoles(t *testing.T) { } func TestRBACModelWithDomains(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") testDomainEnforce(t, e, "alice", "domain1", "data1", "read", true) testDomainEnforce(t, e, "alice", "domain1", "data1", "write", true) @@ -162,7 +162,7 @@ func TestRBACModelWithDomains(t *testing.T) { } func TestRBACModelWithDomainsAtRuntime(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf") e.AddPolicy("admin", "domain1", "data1", "read") e.AddPolicy("admin", "domain1", "data1", "write") @@ -208,7 +208,7 @@ func TestRBACModelWithDomainsAtRuntime(t *testing.T) { func TestRBACModelWithDomainsAtRuntimeMockAdapter(t *testing.T) { adapter := fileadapter.NewAdapterMock("examples/rbac_with_domains_policy.csv") - e := NewEnforcer("examples/rbac_with_domains_model.conf", adapter) + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", adapter) e.AddPolicy("admin", "domain3", "data1", "read") e.AddGroupingPolicy("alice", "admin", "domain3") @@ -225,7 +225,7 @@ func TestRBACModelWithDomainsAtRuntimeMockAdapter(t *testing.T) { } func TestRBACModelWithDeny(t *testing.T) { - e := NewEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_deny_model.conf", "examples/rbac_with_deny_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -238,13 +238,13 @@ func TestRBACModelWithDeny(t *testing.T) { } func TestRBACModelWithOnlyDeny(t *testing.T) { - e := NewEnforcer("examples/rbac_with_not_deny_model.conf", "examples/rbac_with_deny_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_not_deny_model.conf", "examples/rbac_with_deny_policy.csv") testEnforce(t, e, "alice", "data2", "write", false) } func TestRBACModelWithCustomData(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") // You can add custom data to a grouping policy, Casbin will ignore it. It is only meaningful to the caller. // This feature can be used to store information like whether "bob" is an end user (so no subject will inherit "bob") @@ -276,7 +276,7 @@ func TestRBACModelWithCustomData(t *testing.T) { } func TestRBACModelWithPattern(t *testing.T) { - e := NewEnforcer("examples/rbac_with_pattern_model.conf", "examples/rbac_with_pattern_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_pattern_model.conf", "examples/rbac_with_pattern_policy.csv") // Here's a little confusing: the matching function here is not the custom function used in matcher. // It is the matching function used by "g" (and "g2", "g3" if any..) @@ -337,7 +337,7 @@ func (rm *testCustomRoleManager) GetUsers(name string, domain ...string) ([]stri func (rm *testCustomRoleManager) PrintRoles() error { return nil } func TestRBACModelWithCustomRoleManager(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") e.SetRoleManager(NewRoleManager()) e.LoadModel() _ = e.LoadPolicy() @@ -365,7 +365,7 @@ func newTestResource(name string, owner string) testResource { } func TestABACModel(t *testing.T) { - e := NewEnforcer("examples/abac_model.conf") + e, _ := NewEnforcer("examples/abac_model.conf") data1 := newTestResource("data1", "alice") data2 := newTestResource("data2", "bob") @@ -381,7 +381,7 @@ func TestABACModel(t *testing.T) { } func TestKeyMatchModel(t *testing.T) { - e := NewEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv") + e, _ := NewEnforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv") testEnforce(t, e, "alice", "/alice_data/resource1", "GET", true) testEnforce(t, e, "alice", "/alice_data/resource1", "POST", true) @@ -407,7 +407,7 @@ func TestKeyMatchModel(t *testing.T) { } func TestKeyMatch2Model(t *testing.T) { - e := NewEnforcer("examples/keymatch2_model.conf", "examples/keymatch2_policy.csv") + e, _ := NewEnforcer("examples/keymatch2_model.conf", "examples/keymatch2_policy.csv") testEnforce(t, e, "alice", "/alice_data", "GET", false) testEnforce(t, e, "alice", "/alice_data/resource1", "GET", true) @@ -433,7 +433,7 @@ func CustomFunctionWrapper(args ...interface{}) (interface{}, error) { } func TestKeyMatchCustomModel(t *testing.T) { - e := NewEnforcer("examples/keymatch_custom_model.conf", "examples/keymatch2_policy.csv") + e, _ := NewEnforcer("examples/keymatch_custom_model.conf", "examples/keymatch2_policy.csv") e.AddFunction("keyMatchCustom", CustomFunctionWrapper) @@ -442,7 +442,7 @@ func TestKeyMatchCustomModel(t *testing.T) { } func TestIPMatchModel(t *testing.T) { - e := NewEnforcer("examples/ipmatch_model.conf", "examples/ipmatch_policy.csv") + e, _ := NewEnforcer("examples/ipmatch_model.conf", "examples/ipmatch_policy.csv") testEnforce(t, e, "192.168.2.123", "data1", "read", true) testEnforce(t, e, "192.168.2.123", "data1", "write", false) @@ -466,7 +466,7 @@ func TestIPMatchModel(t *testing.T) { } func TestPriorityModel(t *testing.T) { - e := NewEnforcer("examples/priority_model.conf", "examples/priority_policy.csv") + e, _ := NewEnforcer("examples/priority_model.conf", "examples/priority_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) @@ -479,13 +479,13 @@ func TestPriorityModel(t *testing.T) { } func TestPriorityModelIndeterminate(t *testing.T) { - e := NewEnforcer("examples/priority_model.conf", "examples/priority_indeterminate_policy.csv") + e, _ := NewEnforcer("examples/priority_model.conf", "examples/priority_indeterminate_policy.csv") testEnforce(t, e, "alice", "data1", "read", false) } func TestRBACModelInMultiLines(t *testing.T) { - e := NewEnforcer("examples/rbac_model_in_multi_line.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model_in_multi_line.conf", "examples/rbac_policy.csv") testEnforce(t, e, "alice", "data1", "read", true) testEnforce(t, e, "alice", "data1", "write", false) diff --git a/rbac_api.go b/rbac_api.go index 0364893b..9428be3c 100644 --- a/rbac_api.go +++ b/rbac_api.go @@ -187,7 +187,7 @@ func (e *Enforcer) GetImplicitPermissionsForUser(user string, domain ...string) // // GetImplicitUsersForPermission("data1", "read") will get: ["alice", "bob"]. // Note: only users will be returned, roles (2nd arg in "g") will be excluded. -func (e *Enforcer) GetImplicitUsersForPermission(permission ...string) []string { +func (e *Enforcer) GetImplicitUsersForPermission(permission ...string) ([]string, error) { subjects := e.GetAllSubjects() roles := e.GetAllRoles() @@ -196,10 +196,15 @@ func (e *Enforcer) GetImplicitUsersForPermission(permission ...string) []string res := []string{} for _, user := range users { req := util.JoinSliceAny(user, permission...) - if e.Enforce(req...) { + allowed, err := e.Enforce(req...) + if err != nil { + return nil, err + } + + if allowed { res = append(res, user) } } - return res + return res, nil } diff --git a/rbac_api_test.go b/rbac_api_test.go index f038ce09..7c19a60a 100644 --- a/rbac_api_test.go +++ b/rbac_api_test.go @@ -66,7 +66,7 @@ func testHasRole(t *testing.T, e *Enforcer, name string, role string, res bool) } func TestRoleAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") testGetRoles(t, e, "alice", []string{"data2_admin"}) testGetRoles(t, e, "bob", []string{}) @@ -145,7 +145,7 @@ func testHasPermission(t *testing.T, e *Enforcer, name string, permission []stri } func TestPermissionAPI(t *testing.T) { - e := NewEnforcer("examples/basic_without_resources_model.conf", "examples/basic_without_resources_policy.csv") + 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) @@ -210,7 +210,7 @@ func testGetImplicitRolesInDomain(t *testing.T, e *Enforcer, name string, domain } func TestImplicitRoleAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_with_hierarchy_policy.csv") + 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"}}) @@ -240,7 +240,7 @@ func testGetImplicitPermissionsWithDomain(t *testing.T, e *Enforcer, name string } func TestImplicitPermissionAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_with_hierarchy_policy.csv") + 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"}}) @@ -250,13 +250,13 @@ func TestImplicitPermissionAPI(t *testing.T) { } func TestImplicitPermissionAPIWithDomain(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_hierarchy_with_domains_policy.csv") + 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...) + myRes, _ := e.GetImplicitUsersForPermission(permission...) t.Log("Implicit users for permission: ", permission, ": ", myRes) if !util.ArrayEquals(res, myRes) { @@ -265,7 +265,7 @@ func testGetImplicitUsers(t *testing.T, e *Enforcer, res []string, permission .. } func TestImplicitUserAPI(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_with_hierarchy_policy.csv") + 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") diff --git a/rbac_api_with_domains_test.go b/rbac_api_with_domains_test.go index c8591f5d..1c5c556d 100644 --- a/rbac_api_with_domains_test.go +++ b/rbac_api_with_domains_test.go @@ -42,7 +42,7 @@ func testGetRolesInDomain(t *testing.T, e *Enforcer, name string, domain string, } func TestGetImplicitRolesForDomainUser(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_hierarchy_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_hierarchy_with_domains_policy.csv") // This is only able to retrieve the first level of roles. testGetRolesInDomain(t, e, "alice", "domain1", []string{"role:global_admin"}) @@ -53,7 +53,7 @@ func TestGetImplicitRolesForDomainUser(t *testing.T) { // TestUserAPIWithDomains: Add by Gordon func TestUserAPIWithDomains(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") testGetUsersInDomain(t, e, "admin", "domain1", []string{"alice"}) testGetUsersInDomain(t, e, "non_exist", "domain1", []string{}) @@ -72,7 +72,7 @@ func TestUserAPIWithDomains(t *testing.T) { } func TestRoleAPIWithDomains(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") testGetRolesInDomain(t, e, "alice", "domain1", []string{"admin"}) testGetRolesInDomain(t, e, "bob", "domain1", []string{}) @@ -109,7 +109,7 @@ func testGetPermissionsInDomain(t *testing.T, e *Enforcer, name string, domain s } func TestPermissionAPIInDomain(t *testing.T) { - e := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") + e, _ := NewEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv") testGetPermissionsInDomain(t, e, "alice", "domain1", [][]string{}) testGetPermissionsInDomain(t, e, "bob", "domain1", [][]string{}) diff --git a/watcher_test.go b/watcher_test.go index 5f2258d4..42e93f7a 100644 --- a/watcher_test.go +++ b/watcher_test.go @@ -32,7 +32,7 @@ func (w SampleWatcher) Update() error { } func TestSetWatcher(t *testing.T) { - e := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + e, _ := NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") sampleWatcher := SampleWatcher{} e.SetWatcher(sampleWatcher)