Skip to content

Commit

Permalink
Merge e656551 into 5281b5b
Browse files Browse the repository at this point in the history
  • Loading branch information
aguss787 committed Jul 9, 2020
2 parents 5281b5b + e656551 commit d2a70db
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 68 deletions.
194 changes: 128 additions & 66 deletions enforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"errors"
"fmt"
"strings"
"sync"

"github.com/Knetic/govaluate"
"github.com/casbin/casbin/v2/effect"
Expand Down Expand Up @@ -45,6 +46,7 @@ type Enforcer struct {
autoSave bool
autoBuildRoleLinks bool
autoNotifyWatcher bool
parallel bool
}

// NewEnforcer creates an enforcer via file or DB.
Expand Down Expand Up @@ -173,6 +175,7 @@ func (e *Enforcer) initialize() {
e.autoSave = true
e.autoBuildRoleLinks = true
e.autoNotifyWatcher = true
e.parallel = false
}

// LoadModel reloads the model from the model CONF file.
Expand Down Expand Up @@ -334,6 +337,11 @@ func (e *Enforcer) EnableAutoSave(autoSave bool) {
e.autoSave = autoSave
}

// EnableAutoSave controls whether to save a policy rule automatically to the adapter when it is added or removed.
func (e *Enforcer) EnableParallelPolicyEvaluation(parallel bool) {
e.parallel = parallel
}

// EnableAutoBuildRoleLinks controls whether to rebuild the role inheritance relations when a role is added or deleted.
func (e *Enforcer) EnableAutoBuildRoleLinks(autoBuildRoleLinks bool) {
e.autoBuildRoleLinks = autoBuildRoleLinks
Expand Down Expand Up @@ -366,13 +374,8 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac
return true, nil
}

functions := e.fm.GetFunctions()
if _, ok := e.model["g"]; ok {
for key, ast := range e.model["g"] {
rm := ast.RM
functions[key] = util.GenerateGFunction(rm)
}
}
functions := e.generateFunctions()

var expString string
if matcher == "" {
expString = e.model["m"]["m"].Value
Expand All @@ -382,7 +385,6 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac

var expression *govaluate.EvaluableExpression
hasEval := util.HasEval(expString)

if !hasEval {
expression, err = govaluate.NewEvaluableExpressionWithFunctions(expString, functions)
if err != nil {
Expand Down Expand Up @@ -419,78 +421,49 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac
len(rvals),
rvals)
}
for i, pvals := range e.model["p"]["p"].Policy {
// log.LogPrint("Policy Rule: ", pvals)
if len(e.model["p"]["p"].Tokens) != len(pvals) {
return false, fmt.Errorf(
"invalid policy size: expected %d, got %d, pvals: %v",
len(e.model["p"]["p"].Tokens),
len(pvals),
pvals)
}

parameters.pVals = pvals

if hasEval {
ruleNames := util.GetEvalValue(expString)
var expWithRule = expString
for _, ruleName := range ruleNames {
if j, ok := parameters.pTokens[ruleName]; ok {
rule := util.EscapeAssertion(pvals[j])
expWithRule = util.ReplaceEval(expWithRule, rule)
} else {
return false, errors.New("please make sure rule exists in policy when using eval() in matcher")
}
if e.parallel {
errs := make(chan error)
var wg sync.WaitGroup

expression, err = govaluate.NewEvaluableExpressionWithFunctions(expWithRule, functions)
for i, pvals := range e.model["p"]["p"].Policy {
wg.Add(1)
go func(i int, pvals []string, parameters enforceParameters, expression *govaluate.EvaluableExpression) {
defer wg.Done()
parameters.pVals = pvals
policyEffects[i], matcherResults[i], err = e.evaluatePolicy(parameters, expression, expString, functions)
if err != nil {
return false, fmt.Errorf("p.sub_rule should satisfy the syntax of matcher: %s", err)
errs <- err
}
}

}(i, pvals, parameters, expression)
}

result, err := expression.Eval(parameters)
// log.LogPrint("Result: ", result)
go func() {
wg.Wait()
close(errs)
}()

var err error
for cerr := range errs {
err = cerr
}

if err != nil {
return false, err
}
} else {
for i, pvals := range e.model["p"]["p"].Policy {
parameters.pVals = pvals
policyEffects[i], matcherResults[i], err = e.evaluatePolicy(parameters, expression, expString, functions)

switch result := result.(type) {
case bool:
if !result {
policyEffects[i] = effect.Indeterminate
continue
}
case float64:
if result == 0 {
policyEffects[i] = effect.Indeterminate
continue
} else {
matcherResults[i] = result
if err != nil {
return false, err
}
default:
return false, errors.New("matcher result should be bool, int or float")
}

if j, ok := parameters.pTokens["p_eft"]; ok {
eft := parameters.pVals[j]
if eft == "allow" {
policyEffects[i] = effect.Allow
} else if eft == "deny" {
policyEffects[i] = effect.Deny
} else {
policyEffects[i] = effect.Indeterminate
if e.model["e"]["e"].Value == "priority(p_eft) || deny" && policyEffects[i] != effect.Indeterminate {
break
}
} else {
policyEffects[i] = effect.Allow
}

if e.model["e"]["e"].Value == "priority(p_eft) || deny" {
break
}

}
} else {
policyEffects = make([]effect.Effect, 1)
Expand Down Expand Up @@ -547,7 +520,6 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac
reqStr.WriteString(fmt.Sprintf("%v \n", pval))
}
}

}

log.LogPrint(reqStr.String())
Expand All @@ -556,6 +528,96 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac
return result, nil
}

func (e *Enforcer) evaluatePolicy(parameters enforceParameters, expression *govaluate.EvaluableExpression, expString string, functions map[string]govaluate.ExpressionFunction) (policyEffect effect.Effect, matcherResult float64, err error) {
// log.LogPrint("Policy Rule: ", pvals)
if len(e.model["p"]["p"].Tokens) != len(parameters.pVals) {
err = fmt.Errorf(
"invalid policy size: expected %d, got %d, pvals: %v",
len(e.model["p"]["p"].Tokens),
len(parameters.pVals),
parameters.pVals)
return
}

if expression == nil {
expression, err = e.generateExpressionWithRule(parameters, expString, functions)
if err != nil {
return
}
}

policyEffect, matcherResult, err = e.evaluatePolicyHelper(expression, parameters)
return
}

func (e *Enforcer) evaluatePolicyHelper(expression *govaluate.EvaluableExpression, parameters enforceParameters) (policyEffect effect.Effect, matcherResult float64, err error) {
result, err := expression.Eval(parameters)
// log.LogPrint("Result: ", result)
if err != nil {
return 0, 0, nil
}

switch result := result.(type) {
case bool:
if !result {
return effect.Indeterminate, 0, nil
}
case float64:
if result == 0 {
return effect.Indeterminate, 0, nil
} else {
matcherResult = result
}
default:
return 0, 0, errors.New("matcher result should be bool, int or float")
}

if i, ok := parameters.pTokens["p_eft"]; ok {
eft := parameters.pVals[i]
if eft == "allow" {
policyEffect = effect.Allow
} else if eft == "deny" {
policyEffect = effect.Deny
} else {
policyEffect = effect.Indeterminate
}
} else {
policyEffect = effect.Allow
}
return policyEffect, matcherResult, err
}

func (e *Enforcer) generateExpressionWithRule(parameters enforceParameters, expString string, functions map[string]govaluate.ExpressionFunction) (expression *govaluate.EvaluableExpression, err error) {
ruleNames := util.GetEvalValue(expString)
var expWithRule = expString
for _, ruleName := range ruleNames {
if i, ok := parameters.pTokens[ruleName]; ok {
rule := util.EscapeAssertion(parameters.pVals[i])
expWithRule = util.ReplaceEval(expWithRule, rule)
} else {
return nil, errors.New("please make sure rule exists in policy when using eval() in matcher")
}

expression, err = govaluate.NewEvaluableExpressionWithFunctions(expWithRule, functions)
if err != nil {
return nil, fmt.Errorf("p.sub_rule should satisfy the syntax of matcher: %s", err)
}
}
return expression, nil
}

func (e *Enforcer) generateFunctions() map[string]govaluate.ExpressionFunction {
functions := e.fm.GetFunctions()
if _, ok := e.model["g"]; ok {
for key, ast := range e.model["g"] {
rm := ast.RM
functions[key] = util.GenerateGFunction(rm)
}
}

return functions
}

// 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, error) {
return e.enforce("", nil, rvals...)
Expand Down

0 comments on commit d2a70db

Please sign in to comment.