tizen 2.3.1 release
[framework/web/wearable/wrt-security.git] / ace / engine / PolicyEvaluator.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 : PolicyEvaluator.cpp
21 //  @ Date : 2009-05-06
22 //  @ Author : Samsung
23 //
24 //
25 #include <dpl/assert.h>
26 #include <dpl/foreach.h>
27
28 #include <ace/Attribute.h>
29 #include <ace/PolicyEvaluator.h>
30 #include <ace/TreeNode.h>
31 #include <ace/Policy.h>
32 #include <ace/Rule.h>
33 #include <ace/Attribute.h>
34 #include <ace/SettingsLogic.h>
35 #include <ace-dao-rw/AceDAO.h>
36 #include <ace-dao-ro/PreferenceTypes.h>
37 #include <ace/parser.h>
38
39 using namespace AceDB;
40
41 PolicyEvaluator::~PolicyEvaluator()
42 {
43     delete m_combiner;
44 }
45
46 PolicyEvaluator::PolicyEvaluator(PolicyInformationPoint * pip) :
47     m_uniform_policy(NULL),
48     m_wac_policy(NULL),
49     m_tizen_policy(NULL),
50     m_policy_to_use(PolicyType::WAC2_0),
51     m_combiner(new CombinerImpl()),
52     m_verdictListener(NULL),
53     m_pip(pip)
54 {}
55
56 bool PolicyEvaluator::initPDP()
57 {
58     updatePolicy();
59     // TODO change return value someday to void?
60     return true;
61 }
62
63 bool PolicyEvaluator::fillAttributeWithPolicy()
64 {
65     if (m_attributeSet.empty()) {
66         if (!extractAttributes(m_uniform_policy)) {
67             LogInfo("Warning attribute set cannot be extracted. "
68                     "Returning Deny");
69             return false;
70         }
71         // Adding widget type attribute to distinguish WAC/Tizen widgets
72         /**
73          * This special attribute of WidgetParam type is handled
74          * in PolicyInformationPoint, it is based on WidgetType
75          * fron WRT database.
76          *
77          * It is needed to distinguish cached policy results and cached prompt
78          * responses for different policies (WAC/Tizen/any possible
79          * other in the future).
80          */
81         AceDB::BaseAttributePtr attribute(new AceDB::BaseAttribute());
82         attribute->setName(POLICY_WIDGET_TYPE_ATTRIBUTE_NAME);
83         attribute->setType(AceDB::BaseAttribute::Type::WidgetParam);
84         m_attributeSet.insert(attribute);
85         AceDAO::addAttributes(m_attributeSet);
86     } else {
87         LogDebug("Required attribute set already loaded");
88     }
89     return true;
90 }
91
92 PolicyResult PolicyEvaluator::effectToPolicyResult(Effect effect)
93 {
94     if (Effect::Deny == effect) {
95         return PolicyEffect::DENY;
96     }
97     if (Effect::Undetermined == effect) {
98         return PolicyResult::Value::UNDETERMINED;
99     }
100     if (Effect::PromptOneShot == effect) {
101         return PolicyEffect::PROMPT_ONESHOT;
102     }
103     if (Effect::PromptSession == effect) {
104         return PolicyEffect::PROMPT_SESSION;
105     }
106     if (Effect::PromptBlanket == effect) {
107         return PolicyEffect::PROMPT_BLANKET;
108     }
109     if (Effect::Permit == effect) {
110         return PolicyEffect::PERMIT;
111     }
112     if (Effect::Inapplicable == effect) {
113         return PolicyDecision::Value::NOT_APPLICABLE;
114     }
115     return PolicyEffect::DENY;
116 }
117
118 OptionalExtendedPolicyResult PolicyEvaluator::getPolicyForRequestInternal(
119         bool fromCacheOnly)
120 {
121     //ADD_PROFILING_POINT("Search cached verdict in database", "start");
122
123     OptionalExtendedPolicyResult result = AceDAO::getPolicyResult(m_attributeSet);
124
125     //ADD_PROFILING_POINT("Search cached verdict in database", "stop");
126
127     if (fromCacheOnly || !!result) {
128         return result;
129     }
130
131     //ADD_PROFILING_POINT("EvaluatePolicy", "start");
132
133     ExtendedEffect policyEffect = evaluatePolicies(getCurrentPolicyTree());
134
135     //ADD_PROFILING_POINT("EvaluatePolicy", "stop");
136
137     LogDebug("Policy effect is: " << toString(policyEffect.getEffect()));
138
139     ExtendedPolicyResult exResult(
140         effectToPolicyResult(policyEffect.getEffect()),
141         policyEffect.getRuleId());
142
143     AceDAO::setPolicyResult(this->m_attributeSet, exResult);
144     return OptionalExtendedPolicyResult(exResult);
145 }
146
147 // +----------------+---------+---------+------+--------+
148 // |\User setting   | PERMIT  | PROMPT* | DENY | DEF    |
149 // |      \         |         |         |      |        |
150 // |Policy result\  |         |         |      |        |
151 // |----------------+---------+---------+------+--------+
152 // |PERMIT          | PERMIT  | PROMPT* | DENY | PERMIT |
153 // |----------------+---------+---------+------+--------+
154 // |PROMPT*         | PROMPT* | PR MIN  | DENY | PROMPT*|
155 // |----------------+---------+---------+------+--------+
156 // |DENY            | DENY    | DENY    | DENY | DENY   |
157 // |----------------+---------+---------+------+--------+
158 // |UNDETERMIND     | UNDET   | UNDET   | DENY | UNDET  |
159 // |----------------+---------+---------+------+--------+
160 // |NOT_AP          | PEMIT   | PROMPT* | DENY | NOT_AP |
161 // +----------------+---------+---------+------+--------+
162
163 static PolicyResult getMostRestrict(
164         PreferenceTypes globalPreference,
165         const PolicyResult &policyResult)
166 {
167     if (globalPreference == PreferenceTypes::PREFERENCE_PERMIT
168             && policyResult == PolicyEffect::PERMIT) {
169         return PolicyEffect::PERMIT;
170     }
171
172     if (globalPreference == PreferenceTypes::PREFERENCE_DENY
173             || policyResult == PolicyEffect::DENY) {
174         return PolicyEffect::DENY;
175     }
176
177     if (policyResult == PolicyResult::UNDETERMINED) {
178         return PolicyResult::UNDETERMINED;
179     }
180
181     if (globalPreference == PreferenceTypes::PREFERENCE_DEFAULT) {
182         return policyResult;
183     }
184
185     if (globalPreference == PreferenceTypes::PREFERENCE_ONE_SHOT_PROMPT
186             || policyResult == PolicyEffect::PROMPT_ONESHOT) {
187         return PolicyEffect::PROMPT_ONESHOT;
188     }
189
190     if (globalPreference == PreferenceTypes::PREFERENCE_SESSION_PROMPT
191             || policyResult == PolicyEffect::PROMPT_SESSION) {
192         return PolicyEffect::PROMPT_SESSION;
193     }
194
195     if (globalPreference == PreferenceTypes::PREFERENCE_BLANKET_PROMPT
196             || policyResult == PolicyEffect::PROMPT_BLANKET) {
197         return PolicyEffect::PROMPT_BLANKET;
198     }
199
200     return PolicyEffect::PERMIT;
201 }
202
203 OptionalExtendedPolicyResult PolicyEvaluator::getPolicyForRequestFromCache(
204         const Request &request)
205 {
206     return getPolicyForRequest(request, true);
207 }
208
209 ExtendedPolicyResult PolicyEvaluator::getPolicyForRequest(const Request &request)
210 {
211     auto result = this->getPolicyForRequest(request, false);
212     Assert(!!result
213                     && "Policy always has to be evaluated to valid state");
214     return *result;
215 }
216
217 OptionalExtendedPolicyResult PolicyEvaluator::getPolicyForRequest(
218         const Request &request,
219         bool fromCacheOnly)
220 {
221     //ADD_PROFILING_POINT("getPolicyForRequest", "start");
222     m_attributeSet.clear();
223
224     switch (request.getAppType()) {
225         case Request::APP_TYPE_TIZEN:
226             m_policy_to_use = PolicyType::Tizen;
227             LogDebug("==== Using Tizen policy ====");
228             break;
229         case Request::APP_TYPE_WAC20:
230             m_policy_to_use = PolicyType::WAC2_0;
231             LogDebug("==== Using WAC policy ====");
232             break;
233         default:
234             LogError("Unsupported(unknown) widget type. Access denied.");
235             return OptionalExtendedPolicyResult(
236                 ExtendedPolicyResult(PolicyEffect::DENY));
237     }
238
239     try {
240         // Check which attributes should be used
241         // memory alocated, free in destructor
242         //ADD_PROFILING_POINT("getAttributes", "start");
243         AceDB::AceDAO::getAttributes(&m_attributeSet);
244         //ADD_PROFILING_POINT("getAttributes", "stop");
245
246         // If attributes can't be resolved then check the policy
247         if (!fillAttributeWithPolicy()) {
248             //ADD_PROFILING_POINT("getPolicyForRequest", "stop");
249             return OptionalExtendedPolicyResult(
250                 ExtendedPolicyResult(PolicyEffect::DENY));
251         }
252
253         //ADD_PROFILING_POINT("getAttributesValues", "start");
254         m_pip->getAttributesValues(&request, &m_attributeSet);
255         //ADD_PROFILING_POINT("getAttributesValues", "stop");
256         LogDebug("==== Attributes set by PIP ====");
257         printAttributes(m_attributeSet);
258         LogDebug("==== End of attributes set by PIP ====");
259
260         OptionalExtendedPolicyResult policyResult = getPolicyForRequestInternal(
261                 fromCacheOnly);
262
263         if (!policyResult) {
264             if (!fromCacheOnly) {
265                 LogError("Policy evaluated to NULL value");
266                 Assert(false && "Policy evaluated to NULL value");
267             }
268             return OptionalExtendedPolicyResult();
269         }
270         LogDebug("==== getPolicyForRequestInternal result (PolicyResult): "
271                  << policyResult->policyResult << "=====");
272
273         PreferenceTypes globalPreference =
274                 SettingsLogic::findGlobalUserSettings(request);
275
276         auto ret = getMostRestrict(globalPreference, policyResult->policyResult);
277         //ADD_PROFILING_POINT("getPolicyForRequest", "stop");
278         return OptionalExtendedPolicyResult(
279             ExtendedPolicyResult(ret, policyResult->ruleId));
280
281     } catch (AceDB::AceDAO::Exception::DatabaseError &e) {
282         LogError("Database error");
283         DPL::Exception::DisplayKnownException(e);
284         //ADD_PROFILING_POINT("getPolicyForRequest", "stop");
285         return OptionalExtendedPolicyResult(
286             ExtendedPolicyResult(PolicyEffect::DENY));
287     }
288 }
289
290 bool PolicyEvaluator::extractAttributes(TreeNode* policyTree)
291 {
292     if (NULL == policyTree) {
293         return false;
294     }
295
296     //We check if root target matches. In general the root's target should
297     //be empty. Otherwise it would have to have all the subjects available
298     //specified but just to be on the safe side (and for tests) this checking
299     const Policy * policy =
300             dynamic_cast<const Policy *>(policyTree->getElement());
301     Assert(policy != NULL
302                   && "Policy element has been null while attribute extracting");
303
304     extractTargetAttributes(policy);
305     extractAttributesFromSubtree(policyTree); //Enter recursion
306
307     return true;
308 }
309
310 void PolicyEvaluator::extractTargetAttributes(const Policy *policy)
311 {
312     std::list<const Subject *>::const_iterator it =
313             policy->getSubjects()->begin();
314     for (; it != policy->getSubjects()->end(); ++it) {
315         const std::list<Attribute> & attrList = (*it)->getTargetAttributes();
316         FOREACH(it2, attrList)
317         {
318             BaseAttributePtr attr(
319                     new Attribute((*it2).getName(), (*it2).getMatchFunction(),
320                             (*it2).getType()));
321             m_attributeSet.insert(attr);
322         }
323     }
324 }
325
326 TreeNode * PolicyEvaluator::getCurrentPolicyTree()
327 {
328     TreeNode * currentPolicy = NULL;
329     switch (m_policy_to_use) {
330     case PolicyType::Tizen: {
331         currentPolicy = m_tizen_policy;
332         break;}
333     case PolicyType::WAC2_0: {
334         currentPolicy = m_wac_policy;
335         break;}
336     default: {
337         LogError("Invalid policy type to use");}
338     }
339     return currentPolicy;
340 }
341
342 /**
343  *
344  * @param *root - the root of the original (full) subtree of politics
345  * @param *newRoot - the pointer to the root of the copy (reduced) subtree of politics
346  */
347 void PolicyEvaluator::extractAttributesFromSubtree(const TreeNode *root)
348 {
349     const ChildrenSet & children = root->getChildrenSet();
350
351     for (std::list<TreeNode *>::const_iterator it = children.begin();
352             it != children.end(); ++it) {
353         TreeNode * node = *it;
354         if (node->getTypeID() != TreeNode::Policy
355                 && node->getTypeID() != TreeNode::PolicySet) {
356             //It is not a policy so we may be sure that we have already
357             //checked that SubjectId matches
358             //Add new node to new tree and extract attributes
359
360             extractAttributesFromRules(node);
361         } else { //TreeNode is a Policy or PolicySet
362             const Policy * policy =
363                     dynamic_cast<const Policy *>(node->getElement());
364                     //We will be needing also the attributes from target
365             if (policy) {
366                 extractTargetAttributes(policy);
367             } else {
368                 LogError(" extractAttributesFromSubtree policy=NULL");
369             }
370             //Enter recursion
371             extractAttributesFromSubtree(node);
372         }
373     }
374 }
375
376 bool PolicyEvaluator::extractAttributesFromRules(const TreeNode *root)
377 {
378     Assert(root->getTypeID() == TreeNode::Rule
379        && "Tree structure, extracting attributes from node that is not a rule");
380     Rule * rule = dynamic_cast<Rule *>(root->getElement());Assert
381     (rule != NULL);
382     //Get attributes from rule
383     rule->getAttributes(&m_attributeSet);
384
385     //[CR] consider returned value, because its added only to eliminate errors
386     return true;
387 }
388
389 ExtendedEffect PolicyEvaluator::evaluatePolicies(const TreeNode * root)
390 {
391     if (root == NULL) {
392         LogInfo("Error: policy tree doesn't exist. "
393                 "Probably xml file is missing");
394         return Deny;
395     }
396
397     if (m_attributeSet.empty()) {
398         LogInfo("Warning: evaluatePolicies: attribute set was empty");
399     }
400     m_combiner->setAttributeSet(&m_attributeSet);
401     return m_combiner->combinePolicies(root);
402 }
403
404
405 int PolicyEvaluator::updatePolicy(const char* newPolicy)
406 {
407     LogError("PolicyEvaluator::updatePolicy is DEPRECATED");
408     ConfigurationManager* configMgr = ConfigurationManager::getInstance();
409     if (NULL == configMgr) {
410         LogError("ACE fatal error: failed to create configuration manager");
411         return POLICY_PARSING_ERROR;
412     }
413     int result = POLICY_PARSING_SUCCESS;
414     if (newPolicy == NULL) {
415         LogError("Policy Update: incorrect policy name");
416         return POLICY_FILE_ERROR;
417     }
418     LogDebug("Starting update policy: " << newPolicy);
419
420     Parser parser;
421     TreeNode *backup = m_uniform_policy;
422
423     m_uniform_policy = parser.parse(newPolicy,
424             configMgr->getFullPathToPolicyXMLSchema());
425
426     if (NULL == m_uniform_policy) {
427         m_uniform_policy = backup;
428         LogError("Policy Update: corrupted policy file");
429         result = POLICY_PARSING_ERROR;
430     } else {
431         m_currentPolicyFile = newPolicy;
432         m_wac_policy = m_uniform_policy;  //we must be able to use WAC widgets
433         m_tizen_policy = m_uniform_policy;//we must be able to use Tizen widgets
434         m_attributeSet.clear();
435         backup->releaseResources();
436         LogInfo("Policy Update: successful.");
437         try {
438             AceDAO::resetDatabase();   // TODO: this is strange, but this
439                                        // method is deprecated so not changing
440                                        // it (will disappear with entire method)
441         } catch (AceDAO::Exception::DatabaseError &e) {
442         }
443     }
444     return result;
445 }
446
447 TreeNode * PolicyEvaluator::getDefaultSafePolicyTree(void)
448 {
449     Policy * policy = new Policy;
450     Rule * rule = new Rule;
451     TreeNode * mainTree = NULL,
452              * childTree = NULL;
453
454     policy->setCombineAlgorithm(Policy::CombineAlgorithm::DenyOverride);
455     rule->setEffect(Deny);
456
457     mainTree = new TreeNode(m_uniform_policy, TreeNode::Policy, policy);
458     childTree = new TreeNode(mainTree, TreeNode::Rule, rule);
459     mainTree->addChild(childTree);
460
461     LogError("Loading default safe policy tree");
462     return mainTree;
463 }
464
465 void PolicyEvaluator::updatePolicy()
466 {
467     ConfigurationManager *configMgr = ConfigurationManager::getInstance();
468     Assert(NULL != configMgr && "ACE fatal error: failed to "
469            "create configuration manager");
470     AceDAO::clearPolicyCache();
471     if (NULL != m_uniform_policy) {
472         m_uniform_policy->releaseResources();
473     }
474     Parser parserWac, parserTizen;
475     m_wac_policy = parserWac.parse(
476             configMgr->getFullPathToPolicyFile(PolicyType::WAC2_0),
477             configMgr->getFullPathToPolicyXMLSchema());
478     if (NULL == m_wac_policy) {
479         LogError("ACE fatal error: cannot parse XML file (WAC policy)");
480         m_wac_policy = getDefaultSafePolicyTree();
481     }
482     m_tizen_policy = parserTizen.parse(
483             configMgr->getFullPathToPolicyFile(PolicyType::Tizen),
484             configMgr->getFullPathToPolicyXMLSchema());
485     if (NULL == m_tizen_policy) {
486         LogError("ACE fatal error: cannot parse XML file (Tizen policy)");
487         m_tizen_policy = getDefaultSafePolicyTree();
488     }
489     // Policy set is usefull for releasing all policies in case of
490     // policy change
491     Policy * policySet = new PolicySet();
492     policySet->setCombineAlgorithm(Policy::CombineAlgorithm::DenyOverride);
493     m_uniform_policy = new TreeNode(NULL, TreeNode::PolicySet, policySet);
494     m_uniform_policy->addChild(m_wac_policy);
495     m_uniform_policy->addChild(m_tizen_policy);
496
497     // Creating attribute set for the first time after loading policy
498     // to speed up queries
499     m_attributeSet.clear();
500     fillAttributeWithPolicy();
501 }
502
503 std::string PolicyEvaluator::getCurrentPolicy()
504 {
505     LogError("PolicyEvaluator::getCurrentPolicy is DEPRECATED");
506     return m_currentPolicyFile;
507 }
508
509 const char * toString(Validity validity)
510 {
511     switch (validity) {
512     case Validity::ONCE:
513         return "Once";
514         break;
515     case Validity::SESSION:
516         return "Session";
517     case Validity::ALWAYS:
518         return "Always";
519     default:
520         return "WRONG VALIDITY";
521     }
522 }
523
524 const char * toString(Verdict verdict)
525 {
526     switch (verdict) {
527     case Verdict::VERDICT_PERMIT:
528         return "Permit";
529     case Verdict::VERDICT_DENY:
530         return "Deny";
531     case Verdict::VERDICT_INAPPLICABLE:
532         return "Inapplicable";
533     case Verdict::VERDICT_UNKNOWN:
534         return "Unknown";
535     case Verdict::VERDICT_UNDETERMINED:
536         return "Undetermined";
537     case Verdict::VERDICT_ERROR:
538         return "Error";
539     case Verdict::VERDICT_ASYNC:
540         return "Async";
541     default:
542         return "Wrong verdict value";
543     }
544 }