Beispiel #1
0
        /// <summary>
        /// enforce decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act).
        /// </summary>
        /// <param name="rvals">the request needs to be mediated, usually an array of strings,
        /// can be class instances if ABAC is used.</param>
        /// <returns>whether to allow the request.</returns>
        public Boolean Enforce(params Object[] rvals)
        {
            if (!_enabled)
            {
                return(true);
            }

            Dictionary <String, AbstractFunction> functions = new Dictionary <string, AbstractFunction>();

            foreach (var entry in fm.FunctionDict)
            {
                String key      = entry.Key;
                var    function = entry.Value;

                functions.Add(key, function);
            }
            if (model.Model.ContainsKey("g"))
            {
                foreach (var entry in model.Model["g"])
                {
                    String       key = entry.Key;
                    Assertion    ast = entry.Value;
                    IRoleManager rm  = ast.RM;
                    functions.Add(key, BuiltInFunctions.GenerateGFunction(key, rm));
                }
            }

            String expString   = model.Model["m"]["m"].Value;
            var    interpreter = new Interpreter();

            foreach (var func in functions)
            {
                interpreter.SetFunction(func.Key, func.Value);
            }

            Effect.Effect[] policyEffects;
            float[]         matcherResults;
            int             policyLen;
            object          result = null;

            if ((policyLen = model.Model["p"]["p"].Policy.Count) != 0)
            {
                policyEffects  = new Effect.Effect[policyLen];
                matcherResults = new float[policyLen];

                for (int i = 0; i < model.Model["p"]["p"].Policy.Count; i++)
                {
                    List <String> pvals = model.Model["p"]["p"].Policy[i];
                    Dictionary <String, Object> parameters = new Dictionary <string, object>();
                    for (int j = 0; j < model.Model["r"]["r"].Tokens.Length; j++)
                    {
                        String token = model.Model["r"]["r"].Tokens[j];
                        parameters.Add(token, rvals[j]);
                    }
                    for (int j = 0; j < model.Model["p"]["p"].Tokens.Length; j++)
                    {
                        String token = model.Model["p"]["p"].Tokens[j];
                        parameters.Add(token, pvals[j]);
                    }
                    foreach (var item in parameters)
                    {
                        interpreter.SetVariable(item.Key, item.Value);
                    }
                    result = interpreter.Eval(expString);
                    if (result is Boolean)
                    {
                        if (!((Boolean)result))
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            continue;
                        }
                    }
                    else if (result is float)
                    {
                        if ((float)result == 0)
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            continue;
                        }
                        else
                        {
                            matcherResults[i] = (float)result;
                        }
                    }
                    else
                    {
                        throw new Exception("matcher result should be bool, int or float");
                    }
                    if (parameters.ContainsKey("p_eft"))
                    {
                        String eft = (String)parameters["p_eft"];
                        if (eft.Equals("allow"))
                        {
                            policyEffects[i] = Effect.Effect.Allow;
                        }
                        else if (eft.Equals("deny"))
                        {
                            policyEffects[i] = Effect.Effect.Deny;
                        }
                        else
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                        }
                    }
                    else
                    {
                        policyEffects[i] = Effect.Effect.Allow;
                    }

                    if (model.Model["e"]["e"].Value.Equals("priority(p_eft) || deny"))
                    {
                        break;
                    }
                }
            }
            else
            {
                policyEffects  = new Effect.Effect[1];
                matcherResults = new float[1];

                Dictionary <String, Object> parameters = new Dictionary <string, Object>();
                for (int j = 0; j < model.Model["r"]["r"].Tokens.Length; j++)
                {
                    String token = model.Model["r"]["r"].Tokens[j];
                    parameters.Add(token, rvals[j]);
                }
                for (int j = 0; j < model.Model["p"]["p"].Tokens.Length; j++)
                {
                    String token = model.Model["p"]["p"].Tokens[j];
                    parameters.Add(token, "");
                }

                foreach (var item in parameters)
                {
                    interpreter.SetVariable(item.Key, item.Value);
                }

                result = interpreter.Eval(expString, parameters.Select(x => new Parameter(x.Key, x.Value)).ToArray());

                if ((Boolean)result)
                {
                    policyEffects[0] = Effect.Effect.Allow;
                }
                else
                {
                    policyEffects[0] = Effect.Effect.Indeterminate;
                }
            }
            result = eft.MergeEffects(model.Model["e"]["e"].Value, policyEffects, matcherResults);
            return((Boolean)result);
        }
Beispiel #2
0
        /// <summary>
        /// Decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act).
        /// </summary>
        /// <param name="requestValues">The request needs to be mediated, usually an array of strings,
        /// can be class instances if ABAC is used.</param>
        /// <returns>Whether to allow the request.</returns>
        public bool Enforce(params object[] requestValues)
        {
            if (!_enabled)
            {
                return(true);
            }

            string effect           = model.Model[PermConstants.Section.PolicyEffectSection][PermConstants.DefaultPolicyEffectType].Value;
            var    policyList       = model.Model[PermConstants.Section.PolicySection][PermConstants.DefaultPolicyType].Policy;
            int    policyCount      = model.Model[PermConstants.Section.PolicySection][PermConstants.DefaultPolicyType].Policy.Count;
            string expressionString = model.Model[PermConstants.Section.MatcherSection][PermConstants.DefaultMatcherType].Value;

            int requestTokenCount = ExpressionHandler.RequestTokens.Count;

            if (requestTokenCount != requestValues.Length)
            {
                throw new ArgumentException($"Invalid request size: expected {requestTokenCount}, got {requestValues.Length}.");
            }
            int policyTokenCount = ExpressionHandler.PolicyTokens.Count;

            ExpressionHandler.SetRequestParameters(requestValues);

            bool hasEval = Utility.HasEval(expressionString);

            bool           finalResult     = false;
            IChainEffector chainEffector   = _effector as IChainEffector;
            bool           isChainEffector = chainEffector is not null;

            if (isChainEffector)
            {
                chainEffector.StartChain(effect);

                if (policyCount != 0)
                {
                    foreach (var policyValues in policyList)
                    {
                        if (policyTokenCount != policyValues.Count)
                        {
                            throw new ArgumentException($"Invalid policy size: expected {policyTokenCount}, got {policyValues.Count}.");
                        }

                        ExpressionHandler.SetPolicyParameters(policyValues);

                        bool expressionResult;

                        if (hasEval)
                        {
                            string expressionStringWithRule = RewriteEval(expressionString, ExpressionHandler.PolicyTokens, policyValues);
                            expressionResult = ExpressionHandler.Invoke(expressionStringWithRule, requestValues);
                        }
                        else
                        {
                            expressionResult = ExpressionHandler.Invoke(expressionString, requestValues);
                        }

                        var nowEffect = GetEffect(expressionResult);

                        if (nowEffect is not Effect.Effect.Indeterminate && ExpressionHandler.Parameters.TryGetValue("p_eft", out Parameter parameter))
                        {
                            string policyEffect = parameter.Value as string;
                            nowEffect = policyEffect switch
                            {
                                "allow" => Effect.Effect.Allow,
                                "deny" => Effect.Effect.Deny,
                                _ => Effect.Effect.Indeterminate
                            };
                        }

                        if (chainEffector.TryChain(nowEffect) is false || chainEffector.CanChain is false)
                        {
                            break;
                        }
                    }

                    finalResult = chainEffector.Result;
                }
                else
                {
                    if (hasEval)
                    {
                        throw new ArgumentException("Please make sure rule exists in policy when using eval() in matcher");
                    }

                    var nowEffect = GetEffect(ExpressionHandler.Invoke(expressionString, requestValues));

                    if (chainEffector.TryChain(nowEffect))
                    {
                        finalResult = chainEffector.Result;
                    }
                }

                return(finalResult);
            }

            if (policyCount != 0)
            {
                Effect.Effect[] policyEffects = new Effect.Effect[policyCount];

                for (int i = 0; i < policyCount; i++)
                {
                    IReadOnlyList <string> policyValues = policyList[i];

                    if (policyTokenCount != policyValues.Count)
                    {
                        throw new ArgumentException($"Invalid policy size: expected {policyTokenCount}, got {policyValues.Count}.");
                    }

                    ExpressionHandler.SetPolicyParameters(policyValues);

                    bool expressionResult;

                    if (hasEval)
                    {
                        string expressionStringWithRule = RewriteEval(expressionString, ExpressionHandler.PolicyTokens, policyValues);
                        expressionResult = ExpressionHandler.Invoke(expressionStringWithRule, requestValues);
                    }
                    else
                    {
                        expressionResult = ExpressionHandler.Invoke(expressionString, requestValues);
                    }

                    var nowEffect = GetEffect(expressionResult);

                    if (nowEffect is Effect.Effect.Indeterminate)
                    {
                        policyEffects[i] = nowEffect;
                        continue;
                    }

                    if (ExpressionHandler.Parameters.TryGetValue("p_eft", out Parameter parameter))
                    {
                        string policyEffect = parameter.Value as string;
                        nowEffect = policyEffect switch
                        {
                            "allow" => Effect.Effect.Allow,
                            "deny" => Effect.Effect.Deny,
                            _ => Effect.Effect.Indeterminate
                        };
                    }

                    policyEffects[i] = nowEffect;

                    if (effect.Equals(PermConstants.PolicyEffect.Priority))
                    {
                        break;
                    }
                }

                finalResult = _effector.MergeEffects(effect, policyEffects, null);
            }
            else
            {
                if (hasEval)
                {
                    throw new ArgumentException("Please make sure rule exists in policy when using eval() in matcher");
                }

                var nowEffect = GetEffect(ExpressionHandler.Invoke(expressionString, requestValues));
                finalResult = _effector.MergeEffects(effect, new[] { nowEffect }, null);
            }

            return(finalResult);
        }
Beispiel #3
0
        /// <summary>
        /// enforce decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act).
        /// </summary>
        /// <param name="rvals">the request needs to be mediated, usually an array of strings,
        /// can be class instances if ABAC is used.</param>
        /// <returns>whether to allow the request.</returns>
        public Boolean Enforce(params Object[] rvals)
        {
            if (!_enabled)
            {
                return(true);
            }
            InitializeInterpreter();

            String expString = model.Model["m"]["m"].Value;
            var    ps        = model.Model["r"]["r"].Tokens.Concat(model.Model["p"]["p"].Tokens).Select(x => new Parameter(x, typeof(object))).ToArray();

            Effect.Effect[] policyEffects;
            float[]         matcherResults;
            int             policyLen;
            object          result = null;

            if ((policyLen = model.Model["p"]["p"].Policy.Count) != 0)
            {
                policyEffects  = new Effect.Effect[policyLen];
                matcherResults = new float[policyLen];

                for (int i = 0; i < model.Model["p"]["p"].Policy.Count; i++)
                {
                    List <String> pvals = model.Model["p"]["p"].Policy[i];
                    Dictionary <String, Object> parameters = new Dictionary <string, object>();
                    for (int j = 0; j < model.Model["r"]["r"].Tokens.Length; j++)
                    {
                        String token = model.Model["r"]["r"].Tokens[j];
                        parameters.Add(token, rvals[j]);
                    }
                    for (int j = 0; j < model.Model["p"]["p"].Tokens.Length; j++)
                    {
                        String token = model.Model["p"]["p"].Tokens[j];
                        parameters.Add(token, pvals[j]);
                    }

                    //result = _interpreter.Eval(expString, parameters.Select(x => new Parameter(x.Key, x.Value)).ToArray());
                    if (_parsedExpression == null)
                    {
                        _parsedExpression = _interpreter.Parse(expString, parameters.Select(x => new Parameter(x.Key, x.Value)).ToArray());
                    }

                    result = _parsedExpression.Invoke(parameters.Select(x => x.Value).ToArray());
                    if (result is Boolean)
                    {
                        if (!((Boolean)result))
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            continue;
                        }
                    }
                    else if (result is float)
                    {
                        if ((float)result == 0)
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            continue;
                        }
                        else
                        {
                            matcherResults[i] = (float)result;
                        }
                    }
                    else
                    {
                        throw new Exception("matcher result should be bool, int or float");
                    }
                    if (parameters.ContainsKey("p_eft"))
                    {
                        String eft = (String)parameters["p_eft"];
                        if (eft.Equals("allow"))
                        {
                            policyEffects[i] = Effect.Effect.Allow;
                        }
                        else if (eft.Equals("deny"))
                        {
                            policyEffects[i] = Effect.Effect.Deny;
                        }
                        else
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                        }
                    }
                    else
                    {
                        policyEffects[i] = Effect.Effect.Allow;
                    }

                    if (model.Model["e"]["e"].Value.Equals("priority(p_eft) || deny"))
                    {
                        break;
                    }
                }
            }
            else
            {
                policyEffects  = new Effect.Effect[1];
                matcherResults = new float[1];

                Dictionary <String, Object> parameters = new Dictionary <string, Object>();
                for (int j = 0; j < model.Model["r"]["r"].Tokens.Length; j++)
                {
                    String token = model.Model["r"]["r"].Tokens[j];
                    parameters.Add(token, rvals[j]);
                }
                for (int j = 0; j < model.Model["p"]["p"].Tokens.Length; j++)
                {
                    String token = model.Model["p"]["p"].Tokens[j];
                    parameters.Add(token, "");
                }

                if (_parsedExpression == null)
                {
                    _parsedExpression = _interpreter.Parse(expString, parameters.Select(x => new Parameter(x.Key, x.Value)).ToArray());
                }

                result = _parsedExpression.Invoke(parameters.Select(x => x.Value).ToArray());
                //result = _interpreter.Eval(expString, parameters.Select(x => new Parameter(x.Key, x.Value)).ToArray());

                if ((Boolean)result)
                {
                    policyEffects[0] = Effect.Effect.Allow;
                }
                else
                {
                    policyEffects[0] = Effect.Effect.Indeterminate;
                }
            }
            result = eft.MergeEffects(model.Model["e"]["e"].Value, policyEffects, matcherResults);
            return((Boolean)result);
        }
Beispiel #4
0
        /// <summary>
        /// Decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act).
        /// </summary>
        /// <param name="explains"></param>
        /// <param name="requestValues">The request needs to be mediated, usually an array of strings,
        /// can be class instances if ABAC is used.</param>
        /// <returns>Whether to allow the request.</returns>
        private bool Enforce(IReadOnlyList <object> requestValues, ICollection <IEnumerable <string> > explains = null)
        {
            if (_enabled is false)
            {
                return(true);
            }

            bool   explain          = explains is not null;
            string effect           = model.Model[PermConstants.Section.PolicyEffectSection][PermConstants.DefaultPolicyEffectType].Value;
            var    policyList       = model.Model[PermConstants.Section.PolicySection][PermConstants.DefaultPolicyType].Policy;
            int    policyCount      = model.Model[PermConstants.Section.PolicySection][PermConstants.DefaultPolicyType].Policy.Count;
            string expressionString = model.Model[PermConstants.Section.MatcherSection][PermConstants.DefaultMatcherType].Value;

            int requestTokenCount = ExpressionHandler.RequestTokens.Count;

            if (requestTokenCount != requestValues.Count)
            {
                throw new ArgumentException($"Invalid request size: expected {requestTokenCount}, got {requestValues.Count}.");
            }
            int policyTokenCount = ExpressionHandler.PolicyTokens.Count;

            ExpressionHandler.SetRequestParameters(requestValues);

            bool hasEval = Utility.HasEval(expressionString);

            bool           finalResult     = false;
            IChainEffector chainEffector   = _effector as IChainEffector;
            bool           isChainEffector = chainEffector is not null;

            if (isChainEffector)
            {
                chainEffector.StartChain(effect);

                if (policyCount is not 0)
                {
                    foreach (var policyValues in policyList)
                    {
                        if (policyTokenCount != policyValues.Count)
                        {
                            throw new ArgumentException($"Invalid policy size: expected {policyTokenCount}, got {policyValues.Count}.");
                        }

                        ExpressionHandler.SetPolicyParameters(policyValues);

                        bool expressionResult;

                        if (hasEval)
                        {
                            string expressionStringWithRule = RewriteEval(expressionString, ExpressionHandler.PolicyTokens, policyValues);
                            expressionResult = ExpressionHandler.Invoke(expressionStringWithRule, requestValues);
                        }
                        else
                        {
                            expressionResult = ExpressionHandler.Invoke(expressionString, requestValues);
                        }

                        var nowEffect = GetEffect(expressionResult);

                        if (nowEffect is not Effect.Effect.Indeterminate && ExpressionHandler.Parameters.TryGetValue("p_eft", out Parameter parameter))
                        {
                            string policyEffect = parameter.Value as string;
                            nowEffect = policyEffect switch
                            {
                                "allow" => Effect.Effect.Allow,
                                "deny" => Effect.Effect.Deny,
                                _ => Effect.Effect.Indeterminate
                            };
                        }

                        bool chainResult = chainEffector.TryChain(nowEffect);

                        if (explain && chainEffector.HitPolicy)
                        {
                            explains.Add(policyValues);
                        }

                        if (chainResult is false || chainEffector.CanChain is false)
                        {
                            break;
                        }
                    }

                    finalResult = chainEffector.Result;
                }
                else
                {
                    if (hasEval)
                    {
                        throw new ArgumentException("Please make sure rule exists in policy when using eval() in matcher");
                    }

                    IReadOnlyList <string> policyValues = Enumerable.Repeat(string.Empty, policyTokenCount).ToArray();
                    ExpressionHandler.SetPolicyParameters(policyValues);
                    var nowEffect = GetEffect(ExpressionHandler.Invoke(expressionString, requestValues));

                    if (chainEffector.TryChain(nowEffect))
                    {
                        finalResult = chainEffector.Result;
                    }

                    if (explain && chainEffector.HitPolicy)
                    {
                        explains.Add(policyValues);
                    }
                }

#if !NET45
                if (explain)
                {
                    Logger?.LogEnforceResult(requestValues, finalResult, explains);
                }
                else
                {
                    Logger?.LogEnforceResult(requestValues, finalResult);
                }
#endif
                return(finalResult);
            }

            int hitPolicyIndex;
            if (policyCount != 0)
            {
                Effect.Effect[] policyEffects = new Effect.Effect[policyCount];

                for (int i = 0; i < policyCount; i++)
                {
                    IReadOnlyList <string> policyValues = policyList[i];

                    if (policyTokenCount != policyValues.Count)
                    {
                        throw new ArgumentException($"Invalid policy size: expected {policyTokenCount}, got {policyValues.Count}.");
                    }

                    ExpressionHandler.SetPolicyParameters(policyValues);

                    bool expressionResult;

                    if (hasEval)
                    {
                        string expressionStringWithRule = RewriteEval(expressionString, ExpressionHandler.PolicyTokens, policyValues);
                        expressionResult = ExpressionHandler.Invoke(expressionStringWithRule, requestValues);
                    }
                    else
                    {
                        expressionResult = ExpressionHandler.Invoke(expressionString, requestValues);
                    }

                    var nowEffect = GetEffect(expressionResult);

                    if (nowEffect is Effect.Effect.Indeterminate)
                    {
                        policyEffects[i] = nowEffect;
                        continue;
                    }

                    if (ExpressionHandler.Parameters.TryGetValue("p_eft", out Parameter parameter))
                    {
                        string policyEffect = parameter.Value as string;
                        nowEffect = policyEffect switch
                        {
                            "allow" => Effect.Effect.Allow,
                            "deny" => Effect.Effect.Deny,
                            _ => Effect.Effect.Indeterminate
                        };
                    }

                    policyEffects[i] = nowEffect;

                    if (effect.Equals(PermConstants.PolicyEffect.Priority))
                    {
                        break;
                    }
                }

                finalResult = _effector.MergeEffects(effect, policyEffects, null, out hitPolicyIndex);
            }
            else
            {
                if (hasEval)
                {
                    throw new ArgumentException("Please make sure rule exists in policy when using eval() in matcher");
                }

                IReadOnlyList <string> policyValues = Enumerable.Repeat(string.Empty, policyTokenCount).ToArray();
                ExpressionHandler.SetPolicyParameters(policyValues);
                var nowEffect = GetEffect(ExpressionHandler.Invoke(expressionString, requestValues));
                finalResult = _effector.MergeEffects(effect, new[] { nowEffect }, null, out hitPolicyIndex);
            }

            if (explain && hitPolicyIndex is not - 1)
            {
                explains.Add(policyList[hitPolicyIndex]);
            }

#if !NET45
            if (explain)
            {
                Logger?.LogEnforceResult(requestValues, finalResult, explains);
            }
            else
            {
                Logger?.LogEnforceResult(requestValues, finalResult);
            }
#endif
            return(finalResult);
        }
Beispiel #5
0
        /// <summary>
        /// enforce decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act).
        /// </summary>
        /// <param name="rvals">the request needs to be mediated, usually an array of strings,
        /// can be class instances if ABAC is used.</param>
        /// <returns>whether to allow the request.</returns>
        public bool Enforce(params object[] rvals)
        {
            if (!_enabled)
            {
                return(true);
            }

            string effect     = model.Model["e"]["e"].Value;
            var    rTokens    = model.Model["r"]["r"]?.Tokens;
            var    rTokensLen = rTokens?.Count();
            int    policyLen  = model.Model["p"]["p"].Policy.Count;

            Effect.Effect[] policyEffects;
            float[]         matcherResults;
            object          result = null;

            string expString  = model.Model["m"]["m"].Value;
            Lambda expression = null;

            if (matcherMap.ContainsKey(expString))
            {
                expression = matcherMap[expString];
            }
            else
            {
                expression            = GetAndInitializeExpression(rvals);
                matcherMap[expString] = expression;
            }

            if (policyLen != 0)
            {
                policyEffects  = new Effect.Effect[policyLen];
                matcherResults = new float[policyLen];
                for (int i = 0; i < policyLen; i++)
                {
                    List <string> pvals = model.Model["p"]["p"].Policy[i];
                    if (rTokensLen != rvals.Length)
                    {
                        throw new Exception($"invalid request size: expected {rTokensLen}, got {rvals.Length}, rvals: ${rvals}");
                    }
                    var parameters = GetParameters(rvals, pvals);
                    result = expression.Invoke(parameters);
                    if (result is bool)
                    {
                        if (!(bool)result)
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            continue;
                        }
                    }
                    else if (result is float)
                    {
                        if ((float)result == 0)
                        {
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            continue;
                        }
                        else
                        {
                            matcherResults[i] = (float)result;
                        }
                    }
                    else
                    {
                        throw new Exception("matcher result should be bool, int or float");
                    }

                    if (parameters.Any(x => x.Name == "p_eft"))
                    {
                        string policyEft = parameters.FirstOrDefault(x => x.Name == "p_eft")?.Value as string;
                        switch (policyEft)
                        {
                        case "allow":
                            policyEffects[i] = Effect.Effect.Allow;
                            break;

                        case "deny":
                            policyEffects[i] = Effect.Effect.Deny;
                            break;

                        default:
                            policyEffects[i] = Effect.Effect.Indeterminate;
                            break;
                        }
                    }
                    else
                    {
                        policyEffects[i] = Effect.Effect.Allow;
                    }

                    if (effect.Equals("priority(p_eft) || deny"))
                    {
                        break;
                    }
                }
            }
            else
            {
                policyEffects  = new Effect.Effect[1];
                matcherResults = new float[1];
                result         = expression.Invoke(GetParameters(rvals));
                if ((bool)result)
                {
                    policyEffects[0] = Effect.Effect.Allow;
                }
                else
                {
                    policyEffects[0] = Effect.Effect.Indeterminate;
                }
            }
            result = eft.MergeEffects(effect, policyEffects, matcherResults);
            return((bool)result);
        }
Beispiel #6
0
        /// <summary>
        /// Decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act).
        /// </summary>
        /// <param name="requestValues">The request needs to be mediated, usually an array of strings,
        /// can be class instances if ABAC is used.</param>
        /// <param name="matcher">The custom matcher.</param>
        /// <param name="explains">Collection of matched policy explains</param>
        /// <returns>Whether to allow the request.</returns>
        private bool InternalEnforce(IReadOnlyList <object> requestValues, string matcher = null, ICollection <IEnumerable <string> > explains = null)
        {
            var context = EnforceContext.Create(model, matcher, explains is not null);

            if (context.RequestTokens.Count != requestValues.Count)
            {
                throw new ArgumentException($"Invalid request size: expected {context.RequestTokens.Count}, got {requestValues.Count}.");
            }

            ExpressionHandler.SetRequestParameters(requestValues);

            IChainEffector   chainEffector = _effector as IChainEffector;
            PolicyEffectType effectType    = chainEffector.PolicyEffectType;

            if (chainEffector is not null)
            {
                return(InternalEnforceWithChainEffector(context, chainEffector, requestValues, explains));
            }

            if (effectType is PolicyEffectType.PriorityDenyOverride)
            {
                ThrowHelper.ThrowNotSupportException($"Only {nameof(IChainEffector)} support {nameof(PolicyEffectType.PriorityDenyOverride)} policy effect expression.");
            }

            bool finalResult = false;
            int  hitPolicyIndex;
            int  policyCount = context.Policies.Count;

            if (policyCount != 0)
            {
                Effect.Effect[] policyEffects = new Effect.Effect[policyCount];

                for (int i = 0; i < context.Policies.Count; i++)
                {
                    IReadOnlyList <string> policyValues = context.Policies[i];

                    if (context.PolicyTokens.Count != policyValues.Count)
                    {
                        throw new ArgumentException($"Invalid policy size: expected {context.PolicyTokens.Count}, got {policyValues.Count}.");
                    }

                    ExpressionHandler.SetPolicyParameters(policyValues);

                    bool expressionResult;

                    if (context.HasEval)
                    {
                        string expressionStringWithRule = RewriteEval(context.Matcher, ExpressionHandler.PolicyTokens, policyValues);
                        expressionResult = ExpressionHandler.Invoke(expressionStringWithRule, requestValues);
                    }
                    else
                    {
                        expressionResult = ExpressionHandler.Invoke(context.Matcher, requestValues);
                    }

                    var nowEffect = GetEffect(expressionResult);

                    if (nowEffect is Effect.Effect.Indeterminate)
                    {
                        policyEffects[i] = nowEffect;
                        continue;
                    }

                    if (ExpressionHandler.Parameters.TryGetValue("p_eft", out Parameter parameter))
                    {
                        string policyEffect = parameter.Value as string;
                        nowEffect = policyEffect switch
                        {
                            "allow" => Effect.Effect.Allow,
                            "deny" => Effect.Effect.Deny,
                            _ => Effect.Effect.Indeterminate
                        };
                    }

                    policyEffects[i] = nowEffect;

                    if (context.Effect.Equals(PermConstants.PolicyEffect.Priority))
                    {
                        break;
                    }
                }

                finalResult = _effector.MergeEffects(context.Effect, policyEffects, null, out hitPolicyIndex);
            }
            else
            {
                if (context.HasEval)
                {
                    throw new ArgumentException("Please make sure rule exists in policy when using eval() in matcher");
                }

                IReadOnlyList <string> policyValues = Enumerable.Repeat(string.Empty, context.PolicyTokens.Count).ToArray();
                ExpressionHandler.SetPolicyParameters(policyValues);
                Effect.Effect nowEffect = GetEffect(ExpressionHandler.Invoke(context.Matcher, requestValues));
                finalResult = _effector.MergeEffects(context.Effect, new[] { nowEffect }, null, out hitPolicyIndex);
            }

            if (context.Explain && hitPolicyIndex is not - 1)
            {
                explains.Add(context.Policies[hitPolicyIndex]);
            }

#if !NET45
            if (context.Explain)
            {
                Logger?.LogEnforceResult(requestValues, finalResult, explains);
            }
            else
            {
                Logger?.LogEnforceResult(requestValues, finalResult);
            }
#endif
            return(finalResult);
        }