Ejemplo n.º 1
0
        /// <summary>
        /// Decides whether a "subject" can access a "object" with the operation
        /// "action", input parameters are usually: (sub, obj, act). Works specifically with IChainEffector
        /// </summary>
        /// <param name="context">Storage of enforcer variables</param>
        /// <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="explains">Collection of matched policy explains</param>
        /// <returns>Whether to allow the request.</returns>
        private bool InternalEnforceWithChainEffector(
            EnforceContext context,
            IChainEffector chainEffector,
            IReadOnlyList <object> requestValues         = null,
            ICollection <IEnumerable <string> > explains = null)
        {
            bool finalResult = false;

            chainEffector.StartChain(context.Effect);

            bool hasPriority = context.PolicyAssertion.TryGetPriorityIndex(out int priorityIndex);
            bool isPriorityDenyOverrideEfffet = chainEffector.PolicyEffectType is PolicyEffectType.PriorityDenyOverride;
            int? priority  = null;
            var  nowEffect = Effect.Effect.Indeterminate;

            if (context.Policies.Count is not 0)
            {
                foreach (IReadOnlyList <string> policyValues in context.Policies)
                {
                    if (context.PolicyTokens.Count != policyValues.Count)
                    {
                        throw new ArgumentException($"Invalid policy size: expected {context.PolicyTokens.Count}, got {policyValues.Count}.");
                    }

                    if (hasPriority && isPriorityDenyOverrideEfffet)
                    {
                        if (int.TryParse(policyValues[priorityIndex], out int nowPriority))
                        {
                            if (priority.HasValue && nowPriority != priority.Value &&
                                chainEffector.HitPolicyCount > 0)
                            {
                                break;
                            }
                            priority = nowPriority;
                        }
                    }

                    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);
                    }

                    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 (context.Explain && chainEffector.HitPolicy)
                    {
                        explains.Add(policyValues);
                    }

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

                finalResult = chainEffector.Result;
            }
            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);
                nowEffect = GetEffect(ExpressionHandler.Invoke(context.Matcher, requestValues));

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

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

#if !NET45
            if (context.Explain)
            {
                Logger?.LogEnforceResult(requestValues, finalResult, explains);
            }
            else
            {
                Logger?.LogEnforceResult(requestValues, finalResult);
            }
#endif
            return(finalResult);
        }
Ejemplo n.º 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="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);
        }
Ejemplo n.º 3
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);
        }