2 Copyright (c) 2013, Ford Motor Company
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
11 Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided with the
16 Neither the name of the Ford Motor Company nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
36 #include "utils/logger.h"
37 #include "policy/policy_helper.h"
38 #include "policy/policy_manager_impl.h"
44 CREATE_LOGGERPTR_GLOBAL(logger_, "PolicyManagerImpl")
46 bool Match(const StringsValueType& first_name,
47 const StringsValueType& second_name) {
48 const std::string& first = first_name;
49 const std::string& second = second_name;
50 return (strcasecmp(first.c_str(), second.c_str()) == 0);
53 bool Compare(const StringsValueType& first, const StringsValueType& second) {
54 const std::string& first_str = first;
55 const std::string& second_str = second;
56 return (strcasecmp(first_str.c_str(), second_str.c_str()) < 0);
61 CompareGroupName::CompareGroupName(const StringsValueType& group_name)
62 : group_name_(group_name) {
65 bool CompareGroupName::operator()(
66 const StringsValueType& group_name_to_compare) const {
67 const std::string gn_ = group_name_;
68 const std::string gn_compare = group_name_to_compare;
69 return !(strcasecmp(gn_.c_str(), gn_compare.c_str()));
72 bool operator!=(const policy_table::ApplicationParams& first,
73 const policy_table::ApplicationParams& second) {
74 // TODO(AOleynik): Add comparing of Ford-specific and other parameters
75 if (first.groups.size() != second.groups.size()) {
78 StringsConstItr it_first = first.groups.begin();
79 StringsConstItr it_first_end = first.groups.end();
80 StringsConstItr it_second = second.groups.begin();
81 StringsConstItr it_second_end = second.groups.end();
82 for (; it_first != it_first_end; ++it_first) {
83 CompareGroupName gp(*it_first);
84 StringsConstItr it = std::find_if(it_second, it_second_end, gp);
85 if (it_first_end == it) {
92 CheckAppPolicy::CheckAppPolicy(
93 PolicyManagerImpl* pm, const utils::SharedPtr<policy_table::Table> update)
98 bool CheckAppPolicy::HasSameGroups(const AppPoliciesValueType& app_policy,
99 AppPermissions* perms) const {
100 const std::string app_id = app_policy.first;
101 AppPoliciesConstItr it = pm_->policy_table_snapshot_->policy_table
102 .app_policies.find(app_id);
104 if (app_policy.second.is_string()) {
105 return (it->second.is_string() &&
106 app_policy.second.get_string().compare(it->second.get_string()) == 0);
108 if (it->second.is_string()) {
113 policy_table::Strings groups_new = app_policy.second.groups;
114 std::sort(groups_new.begin(), groups_new.end(), Compare);
116 policy_table::Strings groups_curr = (*it).second.groups;
117 std::sort(groups_curr.begin(), groups_curr.end(), Compare);
119 StringsConstItr it_groups_new = groups_new.begin();
120 StringsConstItr it_groups_new_end = groups_new.end();
122 StringsConstItr it_groups_curr = groups_curr.begin();
123 StringsConstItr it_groups_curr_end = groups_curr.end();
125 StringsConstItr new_it = it_groups_new;
126 StringsConstItr old_it = it_groups_curr;
128 std::pair<StringsConstItr, StringsConstItr> diff;
130 while (it_groups_new_end != new_it && it_groups_curr_end != old_it) {
131 size_t size = ((it_groups_new_end - new_it) > (it_groups_curr_end - old_it)) ? it_groups_curr_end - old_it : it_groups_new_end - new_it;
132 diff = std::mismatch(old_it, old_it + size, new_it, Match);
133 if (it_groups_curr_end == diff.first || it_groups_new_end == diff.second) {
134 new_it = diff.second;
138 if (Compare(*diff.first, *diff.second)) {
139 perms->isAppPermissionsRevoked = true;
140 perms->appRevokedPermissions.push_back(*(diff.first));
141 old_it = ++diff.first;
142 new_it = diff.second;
144 perms->appPermissionsConsentNeeded = true;
146 new_it = ++diff.second;
150 for (StringsConstItr it = old_it; it != it_groups_curr_end; ++it) {
151 perms->isAppPermissionsRevoked = true;
152 perms->appRevokedPermissions.push_back(*it);
155 if (it_groups_new_end != new_it) {
156 perms->appPermissionsConsentNeeded = true;
159 return !(perms->appRevokedPermissions.size() > 0
160 || perms->appPermissionsConsentNeeded);
163 bool CheckAppPolicy::IsNewAppication(const std::string& application_id) const {
164 const policy_table::ApplicationPolicies& current_policies = pm_
165 ->policy_table_snapshot_->policy_table.app_policies;
166 AppPoliciesConstItr it_app_policies_curr = current_policies.begin();
167 AppPoliciesConstItr it_app_policies_curr_end = current_policies.end();
169 for (; it_app_policies_curr != it_app_policies_curr_end;
170 ++it_app_policies_curr) {
172 // Find necessary application in current snapshot
173 const std::string application_id_curr = (*it_app_policies_curr).first;
174 if (application_id == application_id_curr) {
181 void CheckAppPolicy::SendNotification(
182 const AppPoliciesValueType& app_policy) const {
183 // Collecting all available rpcs and their parameters from updated
184 // policies and fill notification data struct
185 Permissions notification_data;
187 // Get current user permissions for groups from DB
188 std::vector<FunctionalGroupPermission> group_permissons;
189 // Get current device_id from application id
190 const std::string device_id = pm_->GetCurrentDeviceId(app_policy.first);
191 if (device_id.empty()) {
192 LOG4CXX_WARN(logger_, "Couldn't find device info for application id "
193 "'" << app_policy.first << "'");
196 pm_->GetUserPermissionsForApp(device_id, app_policy.first, group_permissons);
198 pm_->PrepareNotificationData(update_->policy_table.functional_groupings,
199 app_policy.second.groups,
200 group_permissons, notification_data);
202 const std::string app_id = app_policy.first;
203 LOG4CXX_INFO(logger_, "Send notification for application_id:" << app_id);
204 #if defined (EXTENDED_POLICY)
205 pm_->listener()->OnPermissionsUpdated(app_id, notification_data,
206 policy_table::EnumToJsonString(app_policy.second.default_hmi));
208 // Default_hmi is Ford-specific and should not be used with basic policy
209 const std::string default_hmi;
210 pm_->listener()->OnPermissionsUpdated(app_id, notification_data, default_hmi);
214 void CheckAppPolicy::SendOnPendingPermissions(
215 const AppPoliciesValueType& app_policy, AppPermissions permissions) const {
216 // TODO(AOleynik): Exclude default group(s)
217 if (permissions.appPermissionsConsentNeeded) {
218 #if defined(EXTENDED_POLICY)
219 const policy_table::Strings& groups = app_policy.second.groups;
220 // TODO(IKozyrenko): Check logic if optional container is missing
221 const policy_table::Strings& preconsented_groups = *app_policy.second
222 .preconsented_groups;
224 // TODO(KKolodiy): Use consent_groups to filtrate groups
225 PermissionsList list_of_permissions;
227 groups.begin(), groups.end(),
228 FunctionalGroupInserter(preconsented_groups, list_of_permissions));
229 // TODO(PV): logic has changed.
230 if (!list_of_permissions.empty()) {
231 pm_->app_permissions_diff_.insert(
232 std::make_pair(app_policy.first, permissions));
233 pm_->listener()->OnPendingPermissionChange(app_policy.first);
238 if (permissions.isAppPermissionsRevoked) {
239 pm_->app_permissions_diff_.insert(
240 std::make_pair(app_policy.first, permissions));
241 pm_->listener()->OnPendingPermissionChange(app_policy.first);
245 bool CheckAppPolicy::IsAppRevoked(
246 const AppPoliciesValueType& app_policy) const {
247 // Application params are not initialized = application revoked
249 return app_policy.second.is_null();
252 bool CheckAppPolicy::NicknamesMatch(const std::string app_id,
253 const AppPoliciesValueType& app_policy) const {
254 std::string app_name = pm_->listener()->GetAppName(app_id);
255 if (!app_name.empty() && app_policy.second.nicknames && !app_policy.second.nicknames->empty()) {
256 for (policy_table::Strings::const_iterator it = app_policy.second.nicknames->begin();
257 app_policy.second.nicknames->end() != it; ++it) {
258 std::string temp = *it;
259 if (temp.compare(app_name) == 0) {
268 bool CheckAppPolicy::operator()(const AppPoliciesValueType& app_policy) {
269 policy_table::ApplicationPolicies& current_policies = pm_
270 ->policy_table_snapshot_->policy_table.app_policies;
272 const std::string app_id = app_policy.first;
274 AppPermissions permissions_diff(app_id);
275 #if defined (EXTENDED_POLICY)
276 permissions_diff.priority = policy_table::EnumToJsonString(
277 app_policy.second.priority);
280 // Check revocation for any numeric application ids
281 if (atoi(app_id.c_str()) && IsAppRevoked(app_policy)) {
282 permissions_diff.appRevoked = true;
283 pm_->app_permissions_diff_.insert(std::make_pair(app_id, permissions_diff));
284 pm_->listener()->OnAppRevoked(app_id);
285 policy_table::ApplicationPolicies::iterator it = current_policies.find(
287 // Update snapshot with new policies for application
288 if (it != current_policies.end()) {
289 (*it).second = app_policy.second;
290 it->second.set_to_null();
295 // TODO(PV): do we really need this check?
296 if (IsNewAppication(app_id)) {
297 // Update snapshot with policies for new application
298 current_policies[app_id] = app_policy.second;
299 SendNotification(app_policy);
300 SendOnPendingPermissions(app_policy, permissions_diff);
304 if (!NicknamesMatch(app_id, app_policy)) {
305 permissions_diff.appUnauthorized = true;
306 pm_->app_permissions_diff_.insert(std::make_pair(app_id, permissions_diff));
307 pm_->listener()->OnPendingPermissionChange(app_policy.first);
308 policy_table::ApplicationPolicies::iterator it = current_policies.find(
310 // Update snapshot with new policies for application
311 if (it != current_policies.end()) {
312 (*it).second = app_policy.second;
313 it->second.set_to_null();
318 if (HasSameGroups(app_policy, &permissions_diff)) {
321 "Permissions for application:" << app_id << " wasn't changed.");
325 policy_table::ApplicationPolicies::iterator it = current_policies.find(
327 // Update snapshot with new policies for application
328 (*it).second = app_policy.second;
330 // Don't sent notification for "default"
331 if (kDefaultId != app_id && kDeviceId != app_id) {
332 SendNotification(app_policy);
333 SendOnPendingPermissions(app_policy, permissions_diff);
336 // if 'device' was update with new/other func groups => user consent
337 // for device should be cleared.
338 if (kDeviceId == app_id) {
339 #if defined (EXTENDED_POLICY)
340 // TODO(AOleynik): Check design for more convenient access to policy ext data
341 PTExtRepresentation* pt_ext = dynamic_cast<PTExtRepresentation*>(pm_->policy_table_
344 if (!pt_ext->ResetDeviceConsents()) {
354 FillNotificationData::FillNotificationData(Permissions& data,
355 GroupConsent group_state)
357 switch (group_state) {
359 current_key_ = kAllowedKey;
362 current_key_ = kUserDisallowedKey;
367 bool FillNotificationData::operator()(const RpcValueType& rpc) {
368 Permissions::iterator it = data_.find(rpc.first);
369 // If rpc is present already - update its permissions
370 if (data_.end() != it) {
371 UpdateHMILevels(rpc.second.hmi_levels,
372 (*it).second.hmi_permissions[current_key_]);
373 // TODO(IKozyrenko): Check logic if optional container is missing
374 UpdateParameters(*rpc.second.parameters,
375 (*it).second.parameter_permissions[current_key_]);
378 // If rpc is not present - add its permissions
379 UpdateHMILevels(rpc.second.hmi_levels,
380 data_[rpc.first].hmi_permissions[current_key_]);
381 // TODO(IKozyrenko): Check logic if optional container is missing
382 UpdateParameters(*rpc.second.parameters,
383 data_[rpc.first].parameter_permissions[current_key_]);
389 void FillNotificationData::UpdateHMILevels(
390 const policy_table::HmiLevels& in_hmi, std::set<HMILevel>& out_hmi) {
391 HMILevelsConstItr it_hmi_levels = in_hmi.begin();
392 HMILevelsConstItr it_hmi_levels_end = in_hmi.end();
394 for (; it_hmi_levels != it_hmi_levels_end; ++it_hmi_levels) {
395 out_hmi.insert(policy_table::EnumToJsonString(*it_hmi_levels));
399 void FillNotificationData::UpdateParameters(
400 const policy_table::Parameters& in_parameters,
401 std::set<Parameter>& out_parameter) {
402 ParametersConstItr it_parameters = in_parameters.begin();
403 ParametersConstItr it_parameters_end = in_parameters.end();
405 for (; it_parameters != it_parameters_end; ++it_parameters) {
406 out_parameter.insert(policy_table::EnumToJsonString(*it_parameters));
410 void FillNotificationData::ExcludeDisAllowed() {
411 // Search through filled data and remove permission from allowed, if it was
412 // found in disallowed section
413 Permissions::iterator it = data_.begin();
414 Permissions::const_iterator it_end = data_.end();
416 for (; it != it_end; ++it) {
417 std::set<HMILevel>& allowed_hmi_level = (*it).second.hmi_permissions[kAllowedKey];
418 std::set<HMILevel>& disallowed_hmi_level =
419 (*it).second.hmi_permissions[kUserDisallowedKey];
420 std::set<HMILevel> diff_hmi;
422 std::set_difference(allowed_hmi_level.begin(), allowed_hmi_level.end(),
423 disallowed_hmi_level.begin(), disallowed_hmi_level.end(),
424 std::inserter(diff_hmi, diff_hmi.begin()));
425 // Leave levels, which are not present in disallowed
426 allowed_hmi_level = diff_hmi;
428 std::set<Parameter>& allowed_parameters =
429 (*it).second.parameter_permissions[kAllowedKey];
430 std::set<Parameter>& disallowed_parameters =
431 (*it).second.parameter_permissions[kUserDisallowedKey];
433 std::set<Parameter> diff_params;
435 std::set_difference(allowed_parameters.begin(), allowed_parameters.end(),
436 disallowed_parameters.begin(), disallowed_parameters.end(),
437 std::inserter(diff_params, diff_params.begin()));
439 // Leave parameters, which are not present in disallowed
440 allowed_parameters = diff_params;
444 ProcessFunctionalGroup::ProcessFunctionalGroup(
445 const policy_table::FunctionalGroupings& fg,
446 const std::vector<FunctionalGroupPermission>& group_permissions,
449 group_permissions_(group_permissions),
453 bool ProcessFunctionalGroup::operator()(const StringsValueType& group_name) {
454 const std::string group_name_str = group_name;
455 FuncGroupConstItr it = fg_.find(group_name_str);
457 if (fg_.end() != it) {
458 const policy_table::Rpc& rpcs = (*it).second.rpcs;
459 FillNotificationData filler(data_, GetGroupState(group_name_str));
460 std::for_each(rpcs.begin(), rpcs.end(), filler);
465 GroupConsent ProcessFunctionalGroup::GetGroupState(
466 const std::string& group_name) {
467 std::vector<FunctionalGroupPermission>::const_iterator it =
468 group_permissions_.begin();
469 std::vector<FunctionalGroupPermission>::const_iterator it_end =
470 group_permissions_.end();
471 for (; it != it_end; ++it) {
472 if (group_name == (*it).group_name) {
476 return kGroupUndefined;
479 FunctionalGroupInserter::FunctionalGroupInserter(
480 const policy_table::Strings& preconsented_groups, PermissionsList& list)
482 preconsented_(preconsented_groups) {
485 void FunctionalGroupInserter::operator()(const StringsValueType& group_name) {
486 CompareGroupName name(group_name);
487 if (std::find_if(preconsented_.begin(), preconsented_.end(), name)
488 == preconsented_.end()) {
489 list_.push_back(group_name);
493 void FillFunctionalGroupPermissions(FunctionalGroupIDs& ids,
494 FunctionalGroupNames& names,
496 std::vector<FunctionalGroupPermission>& permissions) {
497 FunctionalGroupIDs::const_iterator it = ids.begin();
498 FunctionalGroupIDs::const_iterator it_end = ids.end();
499 for (; it != it_end; ++it) {
500 FunctionalGroupPermission current_group;
501 current_group.group_id = *it;
502 current_group.group_alias = names[*it].first;
503 current_group.group_name = names[*it].second;
504 current_group.state = state;
505 permissions.push_back(current_group);