tizen beta release
[framework/web/wrt-commons.git] / modules / 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
29 #include <dpl/ace/CombinerImpl.h>
30 #include <dpl/ace/Rule.h>
31 #include <dpl/ace/Policy.h>
32
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;
42
43 std::list<int> * CombinerImpl::convertEffectsToInts(
44         const std::list<Effect> * effects)
45 {
46     std::list<int> * intList = new std::list<int>();
47     for (
48         std::list<Effect>::const_iterator it = effects->begin();
49         it != effects->end();
50         ++it
51         ) {
52         switch (*it) {
53         case Deny:
54             intList->push_back(CombinerImpl::DenyInt);
55             break;
56         case Undetermined:        //jk mb added
57             intList->push_back(CombinerImpl::UndeterminedInt);
58             break;
59         case Permit:
60             intList->push_back(CombinerImpl::PermitInt);
61             break;
62         case PromptBlanket:
63             intList->push_back(CombinerImpl::PromptBlanketInt);
64             break;
65         case PromptOneShot:
66             intList->push_back(CombinerImpl::PromptOneShotInt);
67             break;
68         case PromptSession:
69             intList->push_back(CombinerImpl::PromptSessionInt);
70             break;
71         case Inapplicable:
72             intList->push_back(CombinerImpl::InapplicableInt);
73             break;
74         case NotMatchingTarget:
75             intList->push_back(CombinerImpl::NotMatchingTargetInt);
76             break;
77         case Error:
78             intList->push_back(CombinerImpl::ErrorInt);
79             break;
80         default:
81             Assert(false && "Wrong effect");
82         }
83     }
84     return intList;
85 }
86
87 Effect CombinerImpl::convertIntToEffect(int intEffect)
88 {
89     switch (intEffect) {
90     case DenyInt:
91         return Deny;
92
93     case UndeterminedInt: //jk mb added
94         return Undetermined;
95
96     case PermitInt:
97         return Permit;
98
99     case PromptBlanketInt:
100         return PromptBlanket;
101
102     case PromptOneShotInt:
103         return PromptOneShot;
104
105     case PromptSessionInt:
106         return PromptSession;
107
108     case InapplicableInt:
109         return Inapplicable;
110
111     case NotMatchingTargetInt:
112         return NotMatchingTarget;
113
114     case ErrorInt:
115         return Error;
116
117     default:
118         Assert(false && "Wrong integer in int to Effect conversion");
119         return Error;
120     }
121 }
122
123 Effect CombinerImpl::denyOverrides(const std::list<Effect> & effects)
124 {
125     if (isError(effects)) {
126         return Error;
127     }
128
129     std::list<int> * intList = convertEffectsToInts(&effects);
130
131     int result = InapplicableInt;   //Deny has value 0, Undetermined value 1,  Inapplicable value 6
132
133     std::list<int>::const_iterator it = intList->begin();
134
135     while (it != intList->end()) {
136         int effect = *it;
137         //Use most restrictive policy always
138         result = effect < result ? effect  : result;
139         ++it;
140     }
141     delete intList;
142     return convertIntToEffect(result);
143 }
144
145 Effect CombinerImpl::permitOverrides(const std::list<Effect> & effects)   //mb jk modified
146 { if (isError(effects)) {
147       return Error;
148   }
149
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();
153
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
156   bool flag = false;
157   bool flagUndetermined = false;
158
159   while (it != intList->end()) {
160       int effect = *it;
161
162       if (effect == PermitInt) {
163           result = effect;
164           delete intList;
165           return convertIntToEffect(result);
166       } // no need for further check if "permit" found
167       if (effect == UndeterminedInt) { flagUndetermined = true; } //check for undetermined
168
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
173           result = effect;
174           flag = true;
175       }
176
177       ++it;
178   }
179   delete intList;
180
181   if (flagUndetermined) {
182       return Undetermined;
183   }
184
185   if (!flag) {
186       return Inapplicable;
187   }
188   return convertIntToEffect(result);
189 }
190
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();
193
194   if (isError(effects)) {
195       return Error;
196   }
197
198   for (; it != effects.end(); ++it) {
199       if (*it != InapplicableInt) {
200           return *it;
201       }
202   }
203   return Inapplicable;
204 }
205
206 Effect CombinerImpl::firstMatchingTarget(const std::list<Effect> & effects)
207 {
208     if (isError(effects)) {
209         return Error;
210     }
211     // effect list constains result of policies which target has been matched.
212     //
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).
216     //
217     // So we are intrested in first value on the list.
218     return effects.empty() ? Inapplicable : effects.front();
219 }
220
221 bool CombinerImpl::isError(const std::list<Effect> & effects)
222 {
223     FOREACH(it, effects)
224     {
225         if (Error == *it) {
226             return true;
227         }
228     }
229     return false;
230 }
231
232 Effect CombinerImpl::combineRules(const TreeNode * policy)
233 {
234     const Policy * policyObj = dynamic_cast<const Policy *>(policy->getElement());
235     if (!policyObj) {
236         LogError("dynamic_cast failed. PolicyObj is null.");
237         return Error;
238     }
239
240     Policy::CombineAlgorithm algorithm = policyObj->getCombineAlgorithm();
241
242     Assert(
243         algorithm != Policy::FirstTargetMatching &&
244         "Policy cannot have algorithm first target matching");
245
246     bool isUndetermined = false;
247
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
252         }
253         //Target doesn't match
254         return NotMatchingTarget;
255     }
256     //Get all rules
257     const ChildrenSet & children = policy->getChildrenSet();
258     ChildrenConstIterator it = children.begin();
259     std::list<Effect> effects;
260
261     while (it != children.end()) {
262         const Rule * rule = dynamic_cast<const Rule *>((*it)->getElement());
263
264         if (!rule) {
265             LogError("Error in dynamic_cast. rule is null");
266             return Error;
267         }
268
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
274             break;
275         }
276         ++it;
277     } //end policy children iteration
278
279     //Use combining algorithm
280     Effect ef = combine(policyObj->getCombineAlgorithm(), effects);
281     return ef;
282 }
283
284 //WARNING this method makes an assumption that Policy target is a policy child
285 Effect CombinerImpl::combinePolicies(const TreeNode * policy)
286 {
287     const Policy * policySet = dynamic_cast<const Policy *>(policy->getElement());
288
289     if (!policySet) {
290         LogError("dynamic_cast failed. Policy set is null.");
291         return Error;
292     }
293
294     bool isUndetermined = false;
295     Policy::CombineAlgorithm algorithm = policySet->getCombineAlgorithm();
296
297     if (!checkIfTargetMatches(policySet->getSubjects(), isUndetermined)) {
298         /*   I can't explain this...
299         if (isUndetermined) {
300             if (algorithm == Policy::FirstTargetMatching) {
301                 return Undetermined;
302             }
303         }
304         */
305         //Target doesn't match
306         return NotMatchingTarget;
307     }
308
309     const ChildrenSet & children = policy->getChildrenSet();
310
311     ChildrenConstIterator it = children.begin();
312
313     std::list<Effect> effects;
314
315     while (it != children.end()) {
316         Effect effect;
317
318         if ((*it)->getTypeID() == TreeNode::PolicySet) {
319             effect = combinePolicies(*it);
320             if (effect != NotMatchingTarget) {
321                 effects.push_back(effect);
322             }
323         } else if ((*it)->getTypeID() == TreeNode::Policy) {
324             effect = combineRules(*it);
325             if (effect != NotMatchingTarget) {
326                 effects.push_back(effect);
327             }
328         } else {
329             // [CR] fix it
330             LogError("effect value is not initialized!");
331             return Error;
332         }
333
334         if (algorithm == Policy::FirstTargetMatching && effect !=
335             NotMatchingTarget) {
336             //In First matching target algorithm we may return when first result is found
337             break;
338         }
339         ++it;
340     }
341
342     //Use combining algorithm
343     Effect ef = combine(policySet->getCombineAlgorithm(), effects);
344     return ef;
345 }
346
347 Effect CombinerImpl::combine(Policy::CombineAlgorithm algorithm,
348         std::list<Effect> & effects)
349 {
350     LogDebug("Effects to be combined with algorithm: " << toString(algorithm));
351     showEffectList(effects);
352
353     switch (algorithm) {
354     case Policy::DenyOverride:
355         return denyOverrides(effects);
356         break;
357     case Policy::PermitOverride:
358         return permitOverrides(effects);
359         break;
360     case Policy::FirstApplicable:
361         return firstApplicable(effects);
362         break;
363     case Policy::FirstTargetMatching:
364         return firstMatchingTarget(effects);
365         break;
366     default:
367         Assert(false && "Wrong combining algorithm used");
368         return Error;
369     }
370 }
371
372 /**
373  *
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
377  */
378 bool CombinerImpl::checkIfTargetMatches(
379         const std::list<const Subject *> * subjectsList,
380         bool &isUndetermined)
381 {
382     if (subjectsList->empty()) {
383         return true;
384     }
385
386     std::list<const Subject *>::const_iterator it = subjectsList->begin();
387     bool match = false;
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
392             break;
393         }
394         ++it;
395     }
396
397     #ifdef _DEBUG
398     if (match == Attribute::MRTrue) {
399         LogDebug("Target matches ");
400     } else if (match == Attribute::MRUndetermined) {
401         LogDebug("Target match undetermined ");
402     } else {
403         LogDebug("Target doesn't match");
404     }
405     #endif
406     return match;
407 }
408
409 const char * toString(Effect effect)
410 {
411     const char * temp = "";
412
413     switch (effect) {
414     case Deny:
415         temp = "Deny";
416         break;
417     case Undetermined:
418         temp = "Undetermined";
419         break;
420     case PromptOneShot:
421         temp = "PromptOneShot";
422         break;
423     case PromptSession:
424         temp = "PromptSession";
425         break;
426     case PromptBlanket:
427         temp = "PromptBlanket";
428         break;
429     case Permit:
430         temp = "Permit";
431         break;
432     case Inapplicable:
433         temp = "Inapplicable";
434         break;
435     case NotMatchingTarget:
436         temp = "NotMatchingTarget";
437         break;
438     case Error:
439         temp = "Error";
440         break;
441     default:
442         Assert(false && "Wrong effect");
443     }
444     return temp;
445 }