Commit 0b81ddc7 authored by cdanger's avatar cdanger
Browse files

Refactoring

parent a027264e
......@@ -59,138 +59,7 @@ import com.google.common.collect.ImmutableList;
*/
final class OrderedDPOverridesCombiningAlg extends BaseCombiningAlg<Decidable>
{
private static final class OverridingEffectFirstRuleCombiningAlgEvaluator extends RulesWithSameEffectEvaluator
{
private final ImmutableList<RuleEvaluator> otherRules;
private final DecisionType overriddenEffectAsDecision;
/**
* Instantiates the evaluator a list of rules with same Effect, inferring the effect from the first rule in the list
*
* @param rulesWithSameEffect
* combined Rules, all expected to have the same Effect. Must be non-null and non-empty.
*/
OverridingEffectFirstRuleCombiningAlgEvaluator(final Collection<RuleEvaluator> rulesWithOverridingEffect, final Collection<RuleEvaluator> otherRules)
{
super(rulesWithOverridingEffect);
assert otherRules != null && !otherRules.isEmpty() && rulesWithOverridingEffect.iterator().next().getEffect() != otherRules.iterator().next().getEffect();
// first rule's effect assumed the same for all
this.overriddenEffectAsDecision = otherRules.iterator().next().getEffect() == EffectType.DENY ? DecisionType.DENY : DecisionType.PERMIT;
this.otherRules = ImmutableList.copyOf(otherRules);
}
/**
* Evaluate rules with overridden Effect in the case when the evaluation of the rules with overriding Effect returned Indeterminate
*
* @param indeterminateFromRulesWithOverridingEffect
* Indeterminate result from previous evaluation of rules with overridING effect
* @return final decision
*/
private ExtendedDecision evaluateRulesWithOverriddenEffect(final EvaluationContext context, final ExtendedDecision indeterminateFromRulesWithOverridingEffect)
{
/*
* indeterminateFromRulesWithOverridingEffect's decision assumed Indeterminate{overriding_effect}, overriding_effect = D (resp. P) if overriding Effect is Deny (resp. Permit)
*/
assert indeterminateFromRulesWithOverridingEffect != null && indeterminateFromRulesWithOverridingEffect.getDecision() == DecisionType.INDETERMINATE;
for (final RuleEvaluator rule : otherRules)
{
final DecisionResult evalResult = rule.evaluate(context);
if (evalResult.getDecision() != DecisionType.NOT_APPLICABLE)
{
/**
* decision is the overridden Effect or Indeterminate{overridden_effect}, which we have to combine with previous result (from rules with overriding Effect)
* Indeterminate{overriding_effect}. For example,
* <p>
* IndeterminateD and (IndeterminateP or Permit)
* </p>
* <p>
* OR
* </p>
* <p>
* IndeterminateP and (IndeterminateD or Deny)
* </p>
* <p>
* => IndeterminateDP in both cases
* </p>
*/
return ExtendedDecisions.newIndeterminate(DecisionType.INDETERMINATE, indeterminateFromRulesWithOverridingEffect.getStatus());
}
// Else decision is NotApplicable, do nothing, continue
}
/*
* All other rules (with overridden effect) NotApplicable -> initial Indeterminate result unchanged
*/
return indeterminateFromRulesWithOverridingEffect;
}
/**
* Evaluate rules with overridden Effect in the case when the evaluation of the rules with overriding Effect returned NotApplicable
*
* @return final decision
*/
private ExtendedDecision evaluateRulesWithOverriddenEffect(final EvaluationContext context, final UpdatablePepActions updatablePepActions)
{
ExtendedDecision firstIndeterminateInOverriddenEffect = null;
for (final RuleEvaluator rule : otherRules)
{
final DecisionResult evalResult = rule.evaluate(context);
final DecisionType decision = evalResult.getDecision();
if (decision == overriddenEffectAsDecision)
{
// Permit/Deny
updatablePepActions.add(evalResult.getPepActions());
return evalResult;
}
/*
* If the decision is Indeterminate, save the indeterminate cause for the final Indeterminate result (if first Indeterminate), only used if no other rule with determinate result
* checked above is found.
*/
if (decision == DecisionType.INDETERMINATE && firstIndeterminateInOverriddenEffect == null)
{
// first Indeterminate for overridden effect
firstIndeterminateInOverriddenEffect = evalResult;
}
}
/*
* All decisions were NotApplicable or Indeterminate{overridden_effect}
*/
// at Least One Indeterminate
if (firstIndeterminateInOverriddenEffect != null)
{
return firstIndeterminateInOverriddenEffect;
}
// All decisions were NotApplicable -> NotApplicable
return ExtendedDecisions.SIMPLE_NOT_APPLICABLE;
}
@Override
public ExtendedDecision evaluate(final EvaluationContext context, final UpdatablePepActions updatablePepActions,
final UpdatableList<JAXBElement<IdReferenceType>> updatableApplicablePolicyIdList)
{
final ExtendedDecision extDecisionFromRulesWithOverridingEffect = super.evaluate(context, updatablePepActions, updatableApplicablePolicyIdList);
switch (extDecisionFromRulesWithOverridingEffect.getDecision())
{
case DENY:
case PERMIT:
return extDecisionFromRulesWithOverridingEffect;
case INDETERMINATE:
// Optimize
return evaluateRulesWithOverriddenEffect(context, extDecisionFromRulesWithOverridingEffect);
default:
// NotApplicable
// Optimize
return evaluateRulesWithOverriddenEffect(context, updatablePepActions);
}
}
}
private static final class DPOverridesPolicyCombiningAlgEvaluator extends BaseCombiningAlg.Evaluator<Decidable>
{
......@@ -593,153 +462,4 @@ final class OrderedDPOverridesCombiningAlg extends BaseCombiningAlg<Decidable>
evaluatorIfEmptyRuleWithOverriddenEffectAndNoneWithOverridingOne = CombiningAlgEvaluators.DENY_CONSTANT_EVALUATOR;
}
}
/** {@inheritDoc} */
@Override
public CombiningAlg.Evaluator getInstance(final Iterable<CombiningAlgParameter<? extends Decidable>> params, final Iterable<? extends Decidable> combinedElements)
throws UnsupportedOperationException, IllegalArgumentException
{
/*
* If combined elements are Rules, we can optimize
*/
if (!RuleEvaluator.class.isAssignableFrom(getCombinedElementType()))
{
return new DPOverridesPolicyCombiningAlgEvaluator(Preconditions.checkNotNull(combinedElements), EffectType.DENY);
}
// combined elements are Rules, we can optimize
// if no Rules -> NotApplicable
if (combinedElements == null)
{
LOGGER.warn("{}: no rule to combine -> optimization: replacing with equivalent evaluator returning constant NotApplicable decision", this);
return CombiningAlgEvaluators.NOT_APPLICABLE_CONSTANT_EVALUATOR;
}
final Iterator<? extends Decidable> combinedEltIterator = combinedElements.iterator();
if (!combinedEltIterator.hasNext())
{
// empty (no Rules)
LOGGER.warn("{}: no rule to combine -> optimization: replacing with equivalent evaluator returning constant NotApplicable decision", this);
return CombiningAlgEvaluators.NOT_APPLICABLE_CONSTANT_EVALUATOR;
}
/*
* There is at least one Rule. Prepare to iterate over Rules, we will reorder rules with overriding Effect (e.g. Deny for deny-overrides algorithm) before rules with overridden Effect (e.g.
* Permit for deny-overrides algorithm) since order does not matter and deny decision prevails
*/
final Deque<RuleEvaluator> nonEmptyRulesWithOverridingEffect = new ArrayDeque<>();
final Deque<RuleEvaluator> rulesWithOverriddenEffect = new ArrayDeque<>();
/*
*
* If we find any empty Rule in overridden Effect (no target/condition/pep_action), we don't need to look at other rules with such Effect; since such rule is enough to return the overridden
* Effect as decision, if there is no rule with overriding Effect (e.g. if algorithm is deny-overrides, then if there is no applicable Deny rule, if there is any empty Permit rule, the result
* is Permit)
*/
/*
* if atLeastOneEmptyPermitRule (resp. atLeastOneEmptyDenyRule) in case of deny-overrides (resp. permit-overrides) algorithm
*/
boolean atLeastOneEmptyRuleWithOverriddenEffect = false;
while (combinedEltIterator.hasNext())
{
final RuleEvaluator rule = (RuleEvaluator) combinedEltIterator.next();
if (rule.getEffect() == overridingEffect)
{
/*
* If rule's effect is the overriding Effect and it has no target/condition/pep_actions, then rule will always return this Effect -> {overriding_effect}-overrides alg always evaluates
* to ${overriding_effect} (ignore/remove all other rules). ({overriding_effect} = Permit if algorithm is Permit-overrides, or Deny if algorithm is Deny-overrides in this statement.)
*/
if (rule.isEmptyEquivalent())
{
LOGGER.warn(
"{}: {} with Effect={} is empty (no target/condition/pep_actions) => always returns {} => {} combining algorithm will always return {} => other combined rules have no effect => will be ignored/removed.",
this, rule, this.overridingEffect, this.overridingEffect, this.getId(), this.overridingEffect);
return evaluatorIfEmptyRuleWithOverridingEffect;
}
/*
* Rule is not empty, i.e. has a target/condition, therefore may not necessarily return its (overriding) Effect as decision
*/
nonEmptyRulesWithOverridingEffect.add(rule);
continue;
}
/*
* Rule Effect = {overridden_Effect} (e.g. Permit if algorithm is deny-overrides)
*
* Process rule with overridden Effect only if no empty Rule with such Effect has been found yet. Indeed, as mentioned earlier, if there is an empty rule with such overridden Effect, we
* already know that the result is always the overridden Effect (so no need to process other rules with such Effect), if there is no applicable rule with overridING Effect. Indeed, only
* rules with overriding Effect may change the final result in this case.
*/
if (atLeastOneEmptyRuleWithOverriddenEffect)
{
// ignore this new Rule with overridden Effect
LOGGER.warn(
"{}: Ignoring/removing {} (Effect={}) because it does not affect the result, which is only affected by empty Rule ({}) found previously (always returns {}), and {} rule(s).",
this, rule, overriddenEffect, rulesWithOverriddenEffect, overriddenEffect, overridingEffect);
// continue looking for rules with overriding Effect
continue;
}
// No empty Rule with overridden Effect found yet; what about this one?
if (rule.isEmptyEquivalent())
{
/*
* This is the first declared empty Rule with overridden Effect -> always returns the overridden Effect as decision; we can ignore/remove other Rules with overridden Effect (have no
* effect anymore)
*/
LOGGER.warn(
"{}: {} (Effect={}) is empty (no target/condition/pep_actions) => always returns {} => {} combining algorithm will always return {} unless some {} rule applies => other combined {} rules have no effect => will be ignored/removed.",
this, rule, overriddenEffect, overriddenEffect, this.getId(), overriddenEffect, overridingEffect, overriddenEffect);
atLeastOneEmptyRuleWithOverriddenEffect = true;
rulesWithOverriddenEffect.clear();
rulesWithOverriddenEffect.addLast(rule);
// continue looking for rules with overriding Effect
continue;
}
/*
* Non-empty Rule with overridden Effect
*/
rulesWithOverriddenEffect.addLast(rule);
}
/*
* There is at least one rule and there is no empty Rule with overriding Effect
*/
if (nonEmptyRulesWithOverridingEffect.isEmpty())
{
/*
* no Rule with overriding Effect (whether empty or not) -> at least one Rule with overriding Effect and all rules are rules with overriding Effect
*/
if (atLeastOneEmptyRuleWithOverriddenEffect)
{
/*
* no Rule with overriding Effect but one empty rule with overridden Effect -> final result is the overridden Effect always
*/
LOGGER.warn(
"{}: the only combined rule is empty {} Rule ({}) => {} combining algorithm will always return this {} => optimization: replacing with equivalent evaluator returning constant {} decision",
this, this.overriddenEffect, rulesWithOverriddenEffect, this.getId(), this.overriddenEffect, this.overriddenEffect);
return evaluatorIfEmptyRuleWithOverriddenEffectAndNoneWithOverridingOne;
}
/*
* At least one Rule with overridden Effect and all rules are non-empty rules with same (overridden) Effect
*/
return new CombiningAlgEvaluators.RulesWithSameEffectEvaluator(rulesWithOverriddenEffect);
}
// There is at least one non-empty rule with overriding Effect
if (rulesWithOverriddenEffect.isEmpty())
{
/*
* No rule with overridden Effect -> only non-empty rules with same overriding Effect
*/
return new CombiningAlgEvaluators.RulesWithSameEffectEvaluator(nonEmptyRulesWithOverridingEffect);
}
// At least one Rule with overridden Effect and only non-empty rules with overriding Effect
return new OverridingEffectFirstRuleCombiningAlgEvaluator(nonEmptyRulesWithOverridingEffect, rulesWithOverriddenEffect);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment