OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/chromeos/arc/arc_policy_bridge.h" | |
6 | |
7 #include <memory> | |
8 #include <string> | |
9 #include <utility> | |
10 | |
11 #include "base/json/json_reader.h" | |
12 #include "base/json/json_string_value_serializer.h" | |
13 #include "base/logging.h" | |
14 #include "base/memory/ptr_util.h" | |
15 #include "base/values.h" | |
16 #include "chrome/browser/chromeos/profiles/profile_helper.h" | |
17 #include "chrome/browser/policy/profile_policy_connector.h" | |
18 #include "chrome/browser/policy/profile_policy_connector_factory.h" | |
19 #include "chromeos/network/onc/onc_utils.h" | |
20 #include "components/arc/arc_bridge_service.h" | |
21 #include "components/onc/onc_constants.h" | |
22 #include "components/policy/core/common/policy_map.h" | |
23 #include "components/policy/core/common/policy_namespace.h" | |
24 #include "components/policy/policy_constants.h" | |
25 #include "components/user_manager/user.h" | |
26 #include "mojo/public/cpp/bindings/string.h" | |
27 | |
28 namespace arc { | |
29 | |
30 namespace { | |
31 | |
32 const char kArcGlobalAppRestrictions[] = "globalAppRestrictions"; | |
33 const char kArcCaCerts[] = "caCerts"; | |
34 | |
35 // invert_bool_value: If the Chrome policy and the ARC policy with boolean value | |
36 // have opposite semantics, set this to true so the bool is inverted before | |
37 // being added. Otherwise, set it to false. | |
38 void MapBoolToBool(const std::string& arc_policy_name, | |
39 const std::string& policy_name, | |
40 const policy::PolicyMap& policy_map, | |
41 bool invert_bool_value, | |
42 base::DictionaryValue* filtered_policies) { | |
43 const base::Value* const policy_value = policy_map.GetValue(policy_name); | |
44 if (!policy_value) | |
45 return; | |
46 if (!policy_value->IsType(base::Value::TYPE_BOOLEAN)) { | |
47 LOG(ERROR) << "Policy " << policy_name << " is not a boolean."; | |
48 return; | |
49 } | |
50 bool bool_value; | |
51 policy_value->GetAsBoolean(&bool_value); | |
52 filtered_policies->SetBoolean(arc_policy_name, | |
53 bool_value != invert_bool_value); | |
54 } | |
55 | |
56 // int_true: value of Chrome OS policy for which arc policy is set to true. | |
57 // It is set to false for all other values. | |
58 void MapIntToBool(const std::string& arc_policy_name, | |
59 const std::string& policy_name, | |
60 const policy::PolicyMap& policy_map, | |
61 int int_true, | |
62 base::DictionaryValue* filtered_policies) { | |
63 const base::Value* const policy_value = policy_map.GetValue(policy_name); | |
64 if (!policy_value) | |
65 return; | |
66 if (!policy_value->IsType(base::Value::TYPE_INTEGER)) { | |
67 LOG(ERROR) << "Policy " << policy_name << " is not an integer."; | |
68 return; | |
69 } | |
70 int int_value; | |
71 policy_value->GetAsInteger(&int_value); | |
72 filtered_policies->SetBoolean(arc_policy_name, int_value == int_true); | |
73 } | |
74 | |
75 void AddGlobalAppRestriction(const std::string& arc_app_restriction_name, | |
76 const std::string& policy_name, | |
77 const policy::PolicyMap& policy_map, | |
78 base::DictionaryValue* filtered_policies) { | |
79 const base::Value* const policy_value = policy_map.GetValue(policy_name); | |
80 if (policy_value) { | |
81 base::DictionaryValue* global_app_restrictions = nullptr; | |
82 if (!filtered_policies->GetDictionary(kArcGlobalAppRestrictions, | |
83 &global_app_restrictions)) { | |
84 global_app_restrictions = new base::DictionaryValue(); | |
85 filtered_policies->Set(kArcGlobalAppRestrictions, | |
86 global_app_restrictions); | |
87 } | |
88 global_app_restrictions->SetWithoutPathExpansion( | |
89 arc_app_restriction_name, policy_value->CreateDeepCopy()); | |
90 } | |
91 } | |
92 | |
93 void AddOncCaCertsToPolicies(const policy::PolicyMap& policy_map, | |
94 base::DictionaryValue* filtered_policies) { | |
95 const base::Value* const policy_value = | |
96 policy_map.GetValue(policy::key::kArcCertificatesSyncMode); | |
97 int32_t mode = ArcCertsSyncMode::SYNC_DISABLED; | |
98 | |
99 // Old certs should be uninstalled if the sync is disabled or policy is not | |
100 // set. | |
101 if (!policy_value || !policy_value->GetAsInteger(&mode) || | |
102 mode != ArcCertsSyncMode::COPY_CA_CERTS) { | |
103 return; | |
104 } | |
105 | |
106 // Importing CA certificates from device policy is not allowed. | |
107 // Import only from user policy. | |
108 const base::Value* onc_policy_value = | |
109 policy_map.GetValue(policy::key::kOpenNetworkConfiguration); | |
110 if (!onc_policy_value) { | |
111 VLOG(1) << "onc policy is not set."; | |
112 return; | |
113 } | |
114 std::string onc_blob; | |
115 if (!onc_policy_value->GetAsString(&onc_blob)) { | |
116 LOG(ERROR) << "Value of onc policy has invalid format."; | |
117 return; | |
118 } | |
119 | |
120 base::ListValue certificates; | |
121 { | |
122 base::ListValue unused_network_configs; | |
123 base::DictionaryValue unused_global_network_config; | |
124 if (!chromeos::onc::ParseAndValidateOncForImport( | |
125 onc_blob, onc::ONCSource::ONC_SOURCE_USER_POLICY, | |
126 "" /* no passphrase */, &unused_network_configs, | |
127 &unused_global_network_config, &certificates)) { | |
128 LOG(ERROR) << "Value of onc policy has invalid format =" << onc_blob; | |
129 } | |
130 } | |
131 | |
132 std::unique_ptr<base::ListValue> ca_certs( | |
133 base::MakeUnique<base::ListValue>()); | |
134 for (const auto& entry : certificates) { | |
135 const base::DictionaryValue* certificate = nullptr; | |
136 if (!entry->GetAsDictionary(&certificate)) { | |
137 DLOG(FATAL) << "Value of a certificate entry is not a dictionary " | |
138 << "value."; | |
139 continue; | |
140 } | |
141 | |
142 std::string cert_type; | |
143 certificate->GetStringWithoutPathExpansion(::onc::certificate::kType, | |
144 &cert_type); | |
145 if (cert_type != ::onc::certificate::kAuthority) | |
146 continue; | |
147 | |
148 const base::ListValue* trust_list = nullptr; | |
149 if (!certificate->GetListWithoutPathExpansion( | |
150 ::onc::certificate::kTrustBits, &trust_list)) { | |
151 continue; | |
152 } | |
153 | |
154 bool web_trust_flag = false; | |
155 for (const auto& list_val : *trust_list) { | |
156 std::string trust_type; | |
157 if (!list_val->GetAsString(&trust_type)) | |
158 NOTREACHED(); | |
159 | |
160 if (trust_type == ::onc::certificate::kWeb) { | |
161 // "Web" implies that the certificate is to be trusted for SSL | |
162 // identification. | |
163 web_trust_flag = true; | |
164 break; | |
165 } | |
166 } | |
167 if (!web_trust_flag) | |
168 continue; | |
169 | |
170 std::string x509_data; | |
171 if (!certificate->GetStringWithoutPathExpansion(::onc::certificate::kX509, | |
172 &x509_data)) { | |
173 continue; | |
174 } | |
175 | |
176 base::DictionaryValue data; | |
177 data.SetString("X509", x509_data); | |
178 ca_certs->Append(data.CreateDeepCopy()); | |
179 } | |
180 filtered_policies->Set(kArcCaCerts, std::move(ca_certs)); | |
181 } | |
182 | |
183 std::string GetFilteredJSONPolicies(const policy::PolicyMap& policy_map) { | |
184 base::DictionaryValue filtered_policies; | |
185 // Parse ArcPolicy as JSON string before adding other policies to the | |
186 // dictionary. | |
187 const base::Value* const app_policy_value = | |
188 policy_map.GetValue(policy::key::kArcPolicy); | |
189 if (app_policy_value) { | |
190 std::string app_policy_string; | |
191 app_policy_value->GetAsString(&app_policy_string); | |
192 std::unique_ptr<base::DictionaryValue> app_policy_dict = | |
193 base::DictionaryValue::From(base::JSONReader::Read(app_policy_string)); | |
194 if (app_policy_dict) { | |
195 // Need a deep copy of all values here instead of doing a swap, because | |
196 // JSONReader::Read constructs a dictionary whose StringValues are | |
197 // JSONStringValues which are based on StringPiece instead of string. | |
198 filtered_policies.MergeDictionary(app_policy_dict.get()); | |
199 } else { | |
200 LOG(ERROR) << "Value of ArcPolicy has invalid format: " | |
201 << app_policy_string; | |
202 } | |
203 } | |
204 | |
205 // Keep them sorted by the ARC policy names. | |
206 MapBoolToBool("cameraDisabled", policy::key::kVideoCaptureAllowed, policy_map, | |
207 true, &filtered_policies); | |
208 MapBoolToBool("debuggingFeaturesDisabled", | |
209 policy::key::kDeveloperToolsDisabled, policy_map, false, | |
210 &filtered_policies); | |
211 MapBoolToBool("screenCaptureDisabled", policy::key::kDisableScreenshots, | |
212 policy_map, false, &filtered_policies); | |
213 MapIntToBool("shareLocationDisabled", policy::key::kDefaultGeolocationSetting, | |
214 policy_map, 2 /*BlockGeolocation*/, &filtered_policies); | |
215 MapBoolToBool("unmuteMicrophoneDisabled", policy::key::kAudioCaptureAllowed, | |
216 policy_map, true, &filtered_policies); | |
217 MapBoolToBool("mountPhysicalMediaDisabled", | |
218 policy::key::kExternalStorageDisabled, policy_map, false, | |
219 &filtered_policies); | |
220 | |
221 // Add global app restrictions. | |
222 AddGlobalAppRestriction("com.android.browser:URLBlacklist", | |
223 policy::key::kURLBlacklist, policy_map, | |
224 &filtered_policies); | |
225 AddGlobalAppRestriction("com.android.browser:URLWhitelist", | |
226 policy::key::kURLWhitelist, policy_map, | |
227 &filtered_policies); | |
228 | |
229 // Add CA certificates. | |
230 AddOncCaCertsToPolicies(policy_map, &filtered_policies); | |
231 | |
232 std::string policy_json; | |
233 JSONStringValueSerializer serializer(&policy_json); | |
234 serializer.Serialize(filtered_policies); | |
235 return policy_json; | |
236 } | |
237 | |
238 } // namespace | |
239 | |
240 ArcPolicyBridge::ArcPolicyBridge(ArcBridgeService* bridge_service) | |
241 : ArcService(bridge_service), binding_(this) { | |
242 VLOG(2) << "ArcPolicyBridge::ArcPolicyBridge"; | |
243 arc_bridge_service()->policy()->AddObserver(this); | |
244 } | |
245 | |
246 ArcPolicyBridge::ArcPolicyBridge(ArcBridgeService* bridge_service, | |
247 policy::PolicyService* policy_service) | |
248 : ArcService(bridge_service), | |
249 binding_(this), | |
250 policy_service_(policy_service) { | |
251 VLOG(2) << "ArcPolicyBridge::ArcPolicyBridge(bridge_service, policy_service)"; | |
252 arc_bridge_service()->policy()->AddObserver(this); | |
253 } | |
254 | |
255 ArcPolicyBridge::~ArcPolicyBridge() { | |
256 VLOG(2) << "ArcPolicyBridge::~ArcPolicyBridge"; | |
257 arc_bridge_service()->policy()->RemoveObserver(this); | |
258 } | |
259 | |
260 void ArcPolicyBridge::OverrideIsManagedForTesting(bool is_managed) { | |
261 is_managed_ = is_managed; | |
262 } | |
263 | |
264 void ArcPolicyBridge::OnInstanceReady() { | |
265 VLOG(1) << "ArcPolicyBridge::OnPolicyInstanceReady"; | |
266 if (policy_service_ == nullptr) { | |
267 InitializePolicyService(); | |
268 } | |
269 policy_service_->AddObserver(policy::POLICY_DOMAIN_CHROME, this); | |
270 | |
271 mojom::PolicyInstance* const policy_instance = | |
272 arc_bridge_service()->policy()->GetInstanceForMethod("Init"); | |
273 DCHECK(policy_instance); | |
274 policy_instance->Init(binding_.CreateInterfacePtrAndBind()); | |
275 } | |
276 | |
277 void ArcPolicyBridge::OnInstanceClosed() { | |
278 VLOG(1) << "ArcPolicyBridge::OnPolicyInstanceClosed"; | |
279 policy_service_->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this); | |
280 policy_service_ = nullptr; | |
281 } | |
282 | |
283 void ArcPolicyBridge::GetPolicies(const GetPoliciesCallback& callback) { | |
284 VLOG(1) << "ArcPolicyBridge::GetPolicies"; | |
285 if (!is_managed_) { | |
286 callback.Run(mojo::String("")); | |
287 return; | |
288 } | |
289 const policy::PolicyNamespace policy_namespace(policy::POLICY_DOMAIN_CHROME, | |
290 std::string()); | |
291 const policy::PolicyMap& policy_map = | |
292 policy_service_->GetPolicies(policy_namespace); | |
293 const std::string json_policies = GetFilteredJSONPolicies(policy_map); | |
294 callback.Run(mojo::String(json_policies)); | |
295 } | |
296 | |
297 void ArcPolicyBridge::OnPolicyUpdated(const policy::PolicyNamespace& ns, | |
298 const policy::PolicyMap& previous, | |
299 const policy::PolicyMap& current) { | |
300 VLOG(1) << "ArcPolicyBridge::OnPolicyUpdated"; | |
301 auto* instance = | |
302 arc_bridge_service()->policy()->GetInstanceForMethod("OnPolicyUpdated"); | |
303 if (!instance) | |
304 return; | |
305 instance->OnPolicyUpdated(); | |
306 } | |
307 | |
308 void ArcPolicyBridge::InitializePolicyService() { | |
309 const user_manager::User* const primary_user = | |
310 user_manager::UserManager::Get()->GetPrimaryUser(); | |
311 Profile* const profile = | |
312 chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user); | |
313 auto* profile_policy_connector = | |
314 policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile); | |
315 policy_service_ = profile_policy_connector->policy_service(); | |
316 is_managed_ = profile_policy_connector->IsManaged(); | |
317 } | |
318 | |
319 } // namespace arc | |
OLD | NEW |