2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 // @ Project : Access Control Engine
20 // @ File Name : CombinerImpl.cpp
21 // @ Date : 2009-05-06
26 #include <dpl/log/log.h>
27 #include <dpl/assert.h>
28 #include <dpl/foreach.h>
30 #include <ace/CombinerImpl.h>
32 #include <ace/Policy.h>
36 bool denyOverridesPredecessor(
37 const ExtendedEffect &first,
38 const ExtendedEffect &second)
40 if (first.getEffect() == second.getEffect())
41 return first.getRuleId() < second.getRuleId();
42 return first.getEffect() < second.getEffect();
45 bool permitOverridePredecessor(
46 const ExtendedEffect &first,
47 const ExtendedEffect &second)
49 if (first.getEffect() == second.getEffect())
50 return first.getRuleId() < second.getRuleId();
51 return first.getEffect() > second.getEffect();
54 } //anonymous namespace
56 ExtendedEffect CombinerImpl::denyOverrides(const ExtendedEffectList &effects)
58 if (isError(effects)) {
62 ExtendedEffect result(Inapplicable);
64 FOREACH(it, effects) {
65 if (denyOverridesPredecessor(*it, result)) {
72 ExtendedEffect CombinerImpl::permitOverrides(const ExtendedEffectList &effects)
74 if (isError(effects)) {
78 // This magic number must be bigger that the bigest ruleId number from policy file.
79 ExtendedEffect result(Deny, 999999);
81 //Flag used to indicate that any of Deny,prompt-*,permit options appear
82 //Consequently if flag is true then result should be return, otherwise inapplicable should be returned
84 bool flagUndetermined = false;
87 ExtendedEffect effect = *it;
89 if (effect.getEffect() == Permit) {
91 } // no need for further check if "permit" found
92 if (effect.getEffect() == Undetermined) {
93 flagUndetermined = true;
94 } //check for undetermined
96 //Set the flag and the result even if effect is equal to result
97 //It is done to mark if any "Deny" effect occured
98 if (permitOverridePredecessor(effect, result)
99 && effect.getEffect() != Inapplicable
100 && effect.getEffect() != Undetermined)
107 if (flagUndetermined) {
108 return ExtendedEffect(Undetermined);
112 return ExtendedEffect(Inapplicable);
117 ExtendedEffect CombinerImpl::firstApplicable(
118 const ExtendedEffectList & effects)
120 if (isError(effects)) {
124 FOREACH(it,effects) {
125 if (it->getEffect() != Inapplicable) {
132 ExtendedEffect CombinerImpl::firstMatchingTarget(
133 const ExtendedEffectList &effects)
135 if (isError(effects)) {
138 // effect list constains result of policies which target has been matched.
140 // If target does not match policy result is NotMatchingTarget
141 // NotMatchingTarget values are not stored on the effects list
142 // (you can check it in combinePolicies function).
144 // So we are intrested in first value on the list.
145 return effects.empty() ? Inapplicable : effects.front();
148 bool CombinerImpl::isError(const ExtendedEffectList &effects)
152 if (Error == it->getEffect()) {
159 ExtendedEffect CombinerImpl::combineRules(const TreeNode * policy)
161 const Policy * policyObj = dynamic_cast<const Policy *>(policy->getElement());
163 LogError("dynamic_cast failed. PolicyObj is null.");
167 Policy::CombineAlgorithm algorithm = policyObj->getCombineAlgorithm();
170 algorithm != Policy::FirstTargetMatching &&
171 "Policy cannot have algorithm first target matching");
173 bool isUndetermined = false;
175 if (!checkIfTargetMatches(policyObj->getSubjects(), isUndetermined)) {
176 if (isUndetermined) {
177 //TODO Target is undetermined what should we do now ??
178 //Right now simply return NotMatchingTarget
180 //Target doesn't match
181 return NotMatchingTarget;
184 const ChildrenSet & children = policy->getChildrenSet();
185 ChildrenConstIterator it = children.begin();
186 ExtendedEffectList effects;
188 while (it != children.end()) {
189 const Rule * rule = dynamic_cast<const Rule *>((*it)->getElement());
192 LogError("Error in dynamic_cast. rule is null");
193 return ExtendedEffect(Error);
196 ExtendedEffect effect = rule->evaluateRule(this->getAttributeSet());
197 effects.push_back(effect);
198 if (algorithm == Policy::FirstApplicable && effect.getEffect() != Inapplicable) {
199 //For first applicable algorithm we may stop after evaluating first policy
200 //which has effect other than inapplicable
204 } //end policy children iteration
206 //Use combining algorithm
207 ExtendedEffect ef = combine(policyObj->getCombineAlgorithm(), effects);
211 //WARNING this method makes an assumption that Policy target is a policy child
212 ExtendedEffect CombinerImpl::combinePolicies(const TreeNode * policy)
214 const Policy * policySet = dynamic_cast<const Policy *>(policy->getElement());
217 LogError("dynamic_cast failed. Policy set is null.");
221 bool isUndetermined = false;
222 Policy::CombineAlgorithm algorithm = policySet->getCombineAlgorithm();
224 if (!checkIfTargetMatches(policySet->getSubjects(), isUndetermined)) {
225 /* I can't explain this...
226 if (isUndetermined) {
227 if (algorithm == Policy::FirstTargetMatching) {
232 //Target doesn't match
233 return NotMatchingTarget;
236 const ChildrenSet & children = policy->getChildrenSet();
238 ExtendedEffectList effects;
240 FOREACH(it, children) {
241 ExtendedEffect effect;
243 if ((*it)->getTypeID() == TreeNode::PolicySet) {
244 effect = combinePolicies(*it);
245 if (effect.getEffect() != NotMatchingTarget) {
246 effects.push_back(effect);
248 } else if ((*it)->getTypeID() == TreeNode::Policy) {
249 effect = combineRules(*it);
250 if (effect.getEffect() != NotMatchingTarget) {
251 effects.push_back(effect);
255 LogError("effect value is not initialized!");
256 return ExtendedEffect(Error);
259 if (algorithm == Policy::FirstTargetMatching
260 && effect.getEffect() != NotMatchingTarget)
262 //In First matching target algorithm we may return when first result is found
267 //Use combining algorithm
268 return combine(policySet->getCombineAlgorithm(), effects);
271 ExtendedEffect CombinerImpl::combine(
272 Policy::CombineAlgorithm algorithm,
273 ExtendedEffectList &effects)
276 LogDebug("Effects to be combined with algorithm: " << ::toString(algorithm));
277 showEffectList(effects);
280 case Policy::DenyOverride:
281 return denyOverrides(effects);
283 case Policy::PermitOverride:
284 return permitOverrides(effects);
286 case Policy::FirstApplicable:
287 return firstApplicable(effects);
289 case Policy::FirstTargetMatching:
290 return firstMatchingTarget(effects);
293 Assert(false && "Wrong combining algorithm used");
300 * @param attrSet set of Subject attributes in policy that identifies target
301 * @return true if target is determined and matches, false and isUndertmined is set to true if the target is undetermined
302 * false and isUndetermined set to false if target is determined but doesn't match
304 bool CombinerImpl::checkIfTargetMatches(
305 const std::list<const Subject *> * subjectsList,
306 bool &isUndetermined)
308 if (subjectsList->empty()) {
312 std::list<const Subject *>::const_iterator it = subjectsList->begin();
314 //According to BONDI 1.0 at least one target must match
315 while (it != subjectsList->end()) {
316 match = (*it)->matchSubject(this->getAttributeSet(), isUndetermined);
317 if (match) { //at least one match
324 if (match == Attribute::MRTrue) {
325 LogDebug("Target matches ");
326 } else if (match == Attribute::MRUndetermined) {
327 LogDebug("Target match undetermined ");
329 LogDebug("Target doesn't match");