예제 #1
0
 public void StartChain(string effectExpression)
 {
     EffectExpression = effectExpression ?? throw new ArgumentNullException(nameof(effectExpression));
     PolicyEffectType = ParsePolicyEffectType(EffectExpression);
     CanChain         = true;
     Result           = false;
     HitPolicyCount   = 0;
 }
예제 #2
0
        /// <summary>
        /// Merges all matching results collected by the enforcer into a single decision.
        /// </summary>
        /// <param name="policyEffectType"></param>
        /// <param name="effects"></param>
        /// <param name="results"></param>
        /// <returns></returns>
        private bool MergeEffects(PolicyEffectType policyEffectType, Span <Effect> effects, Span <float> results)
        {
            bool finalResult = false;

            foreach (var effect in effects)
            {
                if (EffectEvaluator.TryEvaluate(effect, policyEffectType, ref finalResult))
                {
                    return(finalResult);
                }
            }
            return(finalResult);
        }
예제 #3
0
        /// <summary>
        /// Merges all matching results collected by the enforcer into a single decision.
        /// </summary>
        /// <param name="policyEffectType"></param>
        /// <param name="effects"></param>
        /// <param name="results"></param>
        /// <param name="hitPolicyIndex"></param>
        /// <returns></returns>
        private static bool MergeEffects(PolicyEffectType policyEffectType, Span <Effect> effects, Span <float> results, out int hitPolicyIndex)
        {
            bool finalResult = false;

            hitPolicyIndex = -1;
            for (int index = 0; index < effects.Length; index++)
            {
                if (EffectEvaluator.TryEvaluate(effects[index], policyEffectType,
                                                ref finalResult, out bool hitPolicy))
                {
                    if (hitPolicy)
                    {
                        hitPolicyIndex = index;
                    }
                    return(finalResult);
                }
            }

            return(finalResult);
        }
예제 #4
0
        internal static bool TryEvaluate(Effect.Effect effect, PolicyEffectType policyEffectType,
                                         ref bool result, out bool hitPolicy)
        {
            hitPolicy = false;

            switch (policyEffectType)
            {
            case PolicyEffectType.AllowOverride:
            {
                result = false;
                if (effect is Effect.Effect.Allow)
                {
                    result    = true;
                    hitPolicy = true;
                    return(true);
                }
            }
            break;

            case PolicyEffectType.DenyOverride:
            {
                result = true;
                if (effect is Effect.Effect.Deny)
                {
                    result    = false;
                    hitPolicy = true;
                    return(true);
                }
            }
            break;

            case PolicyEffectType.AllowAndDeny:
                switch (effect)
                {
                case Effect.Effect.Allow:
                    result    = true;
                    hitPolicy = true;
                    return(false);

                case Effect.Effect.Deny:
                    result    = false;
                    hitPolicy = true;
                    return(true);
                }
                break;

            case PolicyEffectType.Priority:
                switch (effect)
                {
                case Effect.Effect.Allow:
                    result    = true;
                    hitPolicy = true;
                    return(true);

                case Effect.Effect.Deny:
                    result    = false;
                    hitPolicy = true;
                    return(true);
                }
                break;

            case PolicyEffectType.Custom:
                // TODO: Support custom policy effect.
                break;

            default:
                throw new NotSupportedException("Not supported policy effect type.");
            }

            return(false);
        }
예제 #5
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);
        }