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>
29 #include <dpl/ace/CombinerImpl.h>
30 #include <dpl/ace/Rule.h>
31 #include <dpl/ace/Policy.h>
33 const int CombinerImpl::DenyInt = 0, //mb jk changed the numbers !!!!!!!!!!!!!!!!!
34 CombinerImpl::UndeterminedInt = 1, //this one is added
35 CombinerImpl::PromptOneShotInt = 2,
36 CombinerImpl::PromptSessionInt = 3,
37 CombinerImpl::PromptBlanketInt = 4,
38 CombinerImpl::PermitInt = 5,
39 CombinerImpl::InapplicableInt = 6,
40 CombinerImpl::NotMatchingTargetInt = 7,
41 CombinerImpl::ErrorInt = 8;
43 std::list<int> * CombinerImpl::convertEffectsToInts(
44 const std::list<Effect> * effects)
46 std::list<int> * intList = new std::list<int>();
48 std::list<Effect>::const_iterator it = effects->begin();
54 intList->push_back(CombinerImpl::DenyInt);
56 case Undetermined: //jk mb added
57 intList->push_back(CombinerImpl::UndeterminedInt);
60 intList->push_back(CombinerImpl::PermitInt);
63 intList->push_back(CombinerImpl::PromptBlanketInt);
66 intList->push_back(CombinerImpl::PromptOneShotInt);
69 intList->push_back(CombinerImpl::PromptSessionInt);
72 intList->push_back(CombinerImpl::InapplicableInt);
74 case NotMatchingTarget:
75 intList->push_back(CombinerImpl::NotMatchingTargetInt);
78 intList->push_back(CombinerImpl::ErrorInt);
81 Assert(false && "Wrong effect");
87 Effect CombinerImpl::convertIntToEffect(int intEffect)
93 case UndeterminedInt: //jk mb added
99 case PromptBlanketInt:
100 return PromptBlanket;
102 case PromptOneShotInt:
103 return PromptOneShot;
105 case PromptSessionInt:
106 return PromptSession;
108 case InapplicableInt:
111 case NotMatchingTargetInt:
112 return NotMatchingTarget;
118 Assert(false && "Wrong integer in int to Effect conversion");
123 Effect CombinerImpl::denyOverrides(const std::list<Effect> & effects)
125 if (isError(effects)) {
129 std::list<int> * intList = convertEffectsToInts(&effects);
131 int result = InapplicableInt; //Deny has value 0, Undetermined value 1, Inapplicable value 6
133 std::list<int>::const_iterator it = intList->begin();
135 while (it != intList->end()) {
137 //Use most restrictive policy always
138 result = effect < result ? effect : result;
142 return convertIntToEffect(result);
145 Effect CombinerImpl::permitOverrides(const std::list<Effect> & effects) //mb jk modified
146 { if (isError(effects)) {
150 int result = DenyInt; //Deny has value 0, Inapplicable value 5
151 std::list<int> * intList = convertEffectsToInts(&effects);
152 std::list<int>::const_iterator it = intList->begin();
154 //Flag used to indicate that any of Deny,prompt-*,permit options appear
155 //Consequently if flag is true then result should be return, otherwise inapplicable should be returned
157 bool flagUndetermined = false;
159 while (it != intList->end()) {
162 if (effect == PermitInt) {
165 return convertIntToEffect(result);
166 } // no need for further check if "permit" found
167 if (effect == UndeterminedInt) { flagUndetermined = true; } //check for undetermined
169 //Set the flag and the result even if effect is equal to result
170 //It is done to mark if any "Deny" effect occured
171 if (effect >= result && effect != InapplicableInt && effect !=
172 UndeterminedInt) { //check for other results
181 if (flagUndetermined) {
188 return convertIntToEffect(result);
191 Effect CombinerImpl::firstApplicable(const std::list<Effect> & effects) //jk mb modified to comply with BONDI 1.0 ("undetermined" handling)
192 { std::list<Effect>::const_iterator it = effects.begin();
194 if (isError(effects)) {
198 for (; it != effects.end(); ++it) {
199 if (*it != InapplicableInt) {
206 Effect CombinerImpl::firstMatchingTarget(const std::list<Effect> & effects)
208 if (isError(effects)) {
211 // effect list constains result of policies which target has been matched.
213 // If target does not match policy result is NotMatchingTarget
214 // NotMatchingTarget values are not stored on the effects list
215 // (you can check it in combinePolicies function).
217 // So we are intrested in first value on the list.
218 return effects.empty() ? Inapplicable : effects.front();
221 bool CombinerImpl::isError(const std::list<Effect> & effects)
232 Effect CombinerImpl::combineRules(const TreeNode * policy)
234 const Policy * policyObj = dynamic_cast<const Policy *>(policy->getElement());
236 LogError("dynamic_cast failed. PolicyObj is null.");
240 Policy::CombineAlgorithm algorithm = policyObj->getCombineAlgorithm();
243 algorithm != Policy::FirstTargetMatching &&
244 "Policy cannot have algorithm first target matching");
246 bool isUndetermined = false;
248 if (!checkIfTargetMatches(policyObj->getSubjects(), isUndetermined)) {
249 if (isUndetermined) {
250 //TODO Target is undetermined what should we do now ??
251 //Right now simply return NotMatchingTarget
253 //Target doesn't match
254 return NotMatchingTarget;
257 const ChildrenSet & children = policy->getChildrenSet();
258 ChildrenConstIterator it = children.begin();
259 std::list<Effect> effects;
261 while (it != children.end()) {
262 const Rule * rule = dynamic_cast<const Rule *>((*it)->getElement());
265 LogError("Error in dynamic_cast. rule is null");
269 Effect effect = rule->evaluateRule(this->getAttributeSet());
270 effects.push_back(effect);
271 if (algorithm == Policy::FirstApplicable && effect != Inapplicable) {
272 //For first applicable algorithm we may stop after evaluating first policy
273 //which has effect other than inapplicable
277 } //end policy children iteration
279 //Use combining algorithm
280 Effect ef = combine(policyObj->getCombineAlgorithm(), effects);
284 //WARNING this method makes an assumption that Policy target is a policy child
285 Effect CombinerImpl::combinePolicies(const TreeNode * policy)
287 const Policy * policySet = dynamic_cast<const Policy *>(policy->getElement());
290 LogError("dynamic_cast failed. Policy set is null.");
294 bool isUndetermined = false;
295 Policy::CombineAlgorithm algorithm = policySet->getCombineAlgorithm();
297 if (!checkIfTargetMatches(policySet->getSubjects(), isUndetermined)) {
298 /* I can't explain this...
299 if (isUndetermined) {
300 if (algorithm == Policy::FirstTargetMatching) {
305 //Target doesn't match
306 return NotMatchingTarget;
309 const ChildrenSet & children = policy->getChildrenSet();
311 ChildrenConstIterator it = children.begin();
313 std::list<Effect> effects;
315 while (it != children.end()) {
318 if ((*it)->getTypeID() == TreeNode::PolicySet) {
319 effect = combinePolicies(*it);
320 if (effect != NotMatchingTarget) {
321 effects.push_back(effect);
323 } else if ((*it)->getTypeID() == TreeNode::Policy) {
324 effect = combineRules(*it);
325 if (effect != NotMatchingTarget) {
326 effects.push_back(effect);
330 LogError("effect value is not initialized!");
334 if (algorithm == Policy::FirstTargetMatching && effect !=
336 //In First matching target algorithm we may return when first result is found
342 //Use combining algorithm
343 Effect ef = combine(policySet->getCombineAlgorithm(), effects);
347 Effect CombinerImpl::combine(Policy::CombineAlgorithm algorithm,
348 std::list<Effect> & effects)
350 LogDebug("Effects to be combined with algorithm: " << toString(algorithm));
351 showEffectList(effects);
354 case Policy::DenyOverride:
355 return denyOverrides(effects);
357 case Policy::PermitOverride:
358 return permitOverrides(effects);
360 case Policy::FirstApplicable:
361 return firstApplicable(effects);
363 case Policy::FirstTargetMatching:
364 return firstMatchingTarget(effects);
367 Assert(false && "Wrong combining algorithm used");
374 * @param attrSet set of Subject attributes in policy that identifies target
375 * @return true if target is determined and matches, false and isUndertmined is set to true if the target is undetermined
376 * false and isUndetermined set to false if target is determined but doesn't match
378 bool CombinerImpl::checkIfTargetMatches(
379 const std::list<const Subject *> * subjectsList,
380 bool &isUndetermined)
382 if (subjectsList->empty()) {
386 std::list<const Subject *>::const_iterator it = subjectsList->begin();
388 //According to BONDI 1.0 at least one target must match
389 while (it != subjectsList->end()) {
390 match = (*it)->matchSubject(this->getAttributeSet(), isUndetermined);
391 if (match) { //at least one match
398 if (match == Attribute::MRTrue) {
399 LogDebug("Target matches ");
400 } else if (match == Attribute::MRUndetermined) {
401 LogDebug("Target match undetermined ");
403 LogDebug("Target doesn't match");
409 const char * toString(Effect effect)
411 const char * temp = "";
418 temp = "Undetermined";
421 temp = "PromptOneShot";
424 temp = "PromptSession";
427 temp = "PromptBlanket";
433 temp = "Inapplicable";
435 case NotMatchingTarget:
436 temp = "NotMatchingTarget";
442 Assert(false && "Wrong effect");