tizen 2.3.1 release
[framework/web/wearable/wrt-security.git] / ace / engine / CombinerImpl.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 //
17 //
18 //
19 //  @ Project : Access Control Engine
20 //  @ File Name : CombinerImpl.cpp
21 //  @ Date : 2009-05-06
22 //  @ Author : Samsung
23 //
24 //
25
26 #include <dpl/log/log.h>
27 #include <dpl/assert.h>
28 #include <dpl/foreach.h>
29
30 #include <ace/CombinerImpl.h>
31 #include <ace/Rule.h>
32 #include <ace/Policy.h>
33
34 namespace {
35
36 bool denyOverridesPredecessor(
37     const ExtendedEffect &first,
38     const ExtendedEffect &second)
39 {
40     if (first.getEffect() == second.getEffect())
41         return first.getRuleId() < second.getRuleId();
42     return first.getEffect() < second.getEffect();
43 }
44
45 bool permitOverridePredecessor(
46     const ExtendedEffect &first,
47     const ExtendedEffect &second)
48 {
49     if (first.getEffect() == second.getEffect())
50         return first.getRuleId() < second.getRuleId();
51     return first.getEffect() > second.getEffect();
52 }
53
54 } //anonymous namespace
55
56 ExtendedEffect CombinerImpl::denyOverrides(const ExtendedEffectList &effects)
57 {
58     if (isError(effects)) {
59         return Error;
60     }
61
62     ExtendedEffect result(Inapplicable);
63
64     FOREACH(it, effects) {
65         if (denyOverridesPredecessor(*it, result)) {
66             result = *it;
67         }
68     }
69     return result;
70 }
71
72 ExtendedEffect CombinerImpl::permitOverrides(const ExtendedEffectList &effects)
73 {
74     if (isError(effects)) {
75         return Error;
76     }
77
78     // This magic number must be bigger that the bigest ruleId number from policy file.
79     ExtendedEffect result(Deny, 999999);
80
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
83     bool flag = false;
84     bool flagUndetermined = false;
85
86     FOREACH(it,effects) {
87         ExtendedEffect effect = *it;
88
89         if (effect.getEffect() == Permit) {
90             return effect;
91         } // no need for further check if "permit" found
92         if (effect.getEffect() == Undetermined) {
93             flagUndetermined = true;
94         } //check for undetermined
95
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)
101         {
102             result = effect;
103             flag = true;
104         }
105     }
106
107     if (flagUndetermined) {
108         return ExtendedEffect(Undetermined);
109     }
110
111     if (!flag) {
112         return ExtendedEffect(Inapplicable);
113     }
114     return result;
115 }
116
117 ExtendedEffect CombinerImpl::firstApplicable(
118     const ExtendedEffectList & effects)
119 {
120   if (isError(effects)) {
121       return Error;
122   }
123
124   FOREACH(it,effects) {
125       if (it->getEffect() != Inapplicable) {
126           return *it;
127       }
128   }
129   return Inapplicable;
130 }
131
132 ExtendedEffect CombinerImpl::firstMatchingTarget(
133     const ExtendedEffectList &effects)
134 {
135     if (isError(effects)) {
136         return Error;
137     }
138     // effect list constains result of policies which target has been matched.
139     //
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).
143     //
144     // So we are intrested in first value on the list.
145     return effects.empty() ? Inapplicable : effects.front();
146 }
147
148 bool CombinerImpl::isError(const ExtendedEffectList &effects)
149 {
150     FOREACH(it, effects)
151     {
152         if (Error == it->getEffect()) {
153             return true;
154         }
155     }
156     return false;
157 }
158
159 ExtendedEffect CombinerImpl::combineRules(const TreeNode * policy)
160 {
161     const Policy * policyObj = dynamic_cast<const Policy *>(policy->getElement());
162     if (!policyObj) {
163         LogError("dynamic_cast failed. PolicyObj is null.");
164         return Error;
165     }
166
167     Policy::CombineAlgorithm algorithm = policyObj->getCombineAlgorithm();
168
169     Assert(
170         algorithm != Policy::FirstTargetMatching &&
171         "Policy cannot have algorithm first target matching");
172
173     bool isUndetermined = false;
174
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
179         }
180         //Target doesn't match
181         return NotMatchingTarget;
182     }
183     //Get all rules
184     const ChildrenSet & children = policy->getChildrenSet();
185     ChildrenConstIterator it = children.begin();
186     ExtendedEffectList effects;
187
188     while (it != children.end()) {
189         const Rule * rule = dynamic_cast<const Rule *>((*it)->getElement());
190
191         if (!rule) {
192             LogError("Error in dynamic_cast. rule is null");
193             return ExtendedEffect(Error);
194         }
195
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
201             break;
202         }
203         ++it;
204     } //end policy children iteration
205
206     //Use combining algorithm
207     ExtendedEffect ef = combine(policyObj->getCombineAlgorithm(), effects);
208     return ef;
209 }
210
211 //WARNING this method makes an assumption that Policy target is a policy child
212 ExtendedEffect CombinerImpl::combinePolicies(const TreeNode * policy)
213 {
214     const Policy * policySet = dynamic_cast<const Policy *>(policy->getElement());
215
216     if (!policySet) {
217         LogError("dynamic_cast failed. Policy set is null.");
218         return Error;
219     }
220
221     bool isUndetermined = false;
222     Policy::CombineAlgorithm algorithm = policySet->getCombineAlgorithm();
223
224     if (!checkIfTargetMatches(policySet->getSubjects(), isUndetermined)) {
225         /*   I can't explain this...
226         if (isUndetermined) {
227             if (algorithm == Policy::FirstTargetMatching) {
228                 return Undetermined;
229             }
230         }
231         */
232         //Target doesn't match
233         return NotMatchingTarget;
234     }
235
236     const ChildrenSet & children = policy->getChildrenSet();
237
238     ExtendedEffectList effects;
239
240     FOREACH(it, children) {
241         ExtendedEffect effect;
242
243         if ((*it)->getTypeID() == TreeNode::PolicySet) {
244             effect = combinePolicies(*it);
245             if (effect.getEffect() != NotMatchingTarget) {
246                 effects.push_back(effect);
247             }
248         } else if ((*it)->getTypeID() == TreeNode::Policy) {
249             effect = combineRules(*it);
250             if (effect.getEffect() != NotMatchingTarget) {
251                 effects.push_back(effect);
252             }
253         } else {
254             // [CR] fix it
255             LogError("effect value is not initialized!");
256             return ExtendedEffect(Error);
257         }
258
259         if (algorithm == Policy::FirstTargetMatching
260             && effect.getEffect() != NotMatchingTarget)
261         {
262             //In First matching target algorithm we may return when first result is found
263             break;
264         }
265     }
266
267     //Use combining algorithm
268     return combine(policySet->getCombineAlgorithm(), effects);
269 }
270
271 ExtendedEffect CombinerImpl::combine(
272     Policy::CombineAlgorithm algorithm,
273     ExtendedEffectList &effects)
274 {
275 #ifdef ALL_LOGS
276     LogDebug("Effects to be combined with algorithm: " << ::toString(algorithm));
277     showEffectList(effects);
278 #endif
279     switch (algorithm) {
280     case Policy::DenyOverride:
281         return denyOverrides(effects);
282         break;
283     case Policy::PermitOverride:
284         return permitOverrides(effects);
285         break;
286     case Policy::FirstApplicable:
287         return firstApplicable(effects);
288         break;
289     case Policy::FirstTargetMatching:
290         return firstMatchingTarget(effects);
291         break;
292     default:
293         Assert(false && "Wrong combining algorithm used");
294         return Error;
295     }
296 }
297
298 /**
299  *
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
303  */
304 bool CombinerImpl::checkIfTargetMatches(
305         const std::list<const Subject *> * subjectsList,
306         bool &isUndetermined)
307 {
308     if (subjectsList->empty()) {
309         return true;
310     }
311
312     std::list<const Subject *>::const_iterator it = subjectsList->begin();
313     bool match = false;
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
318             break;
319         }
320         ++it;
321     }
322
323     #ifdef _DEBUG
324     if (match == Attribute::MRTrue) {
325         LogDebug("Target matches ");
326     } else if (match == Attribute::MRUndetermined) {
327         LogDebug("Target match undetermined ");
328     } else {
329         LogDebug("Target doesn't match");
330     }
331     #endif
332     return match;
333 }
334