blob: c514db3d031e7270ea0ad640eae347b0a86de564 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 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/ui/webui/policy_ui.h"
6
Torne (Richard Coles)58218062012-11-14 11:43:16 +00007#include "base/bind.h"
8#include "base/bind_helpers.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00009#include "base/callback.h"
10#include "base/compiler_specific.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/memory/weak_ptr.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010014#include "base/strings/string16.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010015#include "base/time/time.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000016#include "base/values.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000017#include "chrome/browser/browser_process.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010018#include "chrome/browser/chrome_notification_types.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000019#include "chrome/browser/policy/browser_policy_connector.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000020#include "chrome/browser/policy/cloud/cloud_policy_client.h"
21#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
22#include "chrome/browser/policy/cloud/cloud_policy_core.h"
23#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
24#include "chrome/browser/policy/cloud/cloud_policy_store.h"
25#include "chrome/browser/policy/cloud/cloud_policy_validator.h"
26#include "chrome/browser/policy/cloud/message_util.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000027#include "chrome/browser/policy/configuration_policy_handler_list.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000028#include "chrome/browser/policy/policy_error_map.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000029#include "chrome/browser/policy/policy_map.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000030#include "chrome/browser/policy/policy_service.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000031#include "chrome/browser/policy/policy_types.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010032#include "chrome/browser/policy/profile_policy_connector.h"
33#include "chrome/browser/policy/profile_policy_connector_factory.h"
34#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000035#include "chrome/browser/profiles/profile.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000036#include "chrome/common/url_constants.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010037#include "content/public/browser/notification_observer.h"
38#include "content/public/browser/notification_registrar.h"
39#include "content/public/browser/notification_service.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000040#include "content/public/browser/web_ui.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000041#include "content/public/browser/web_ui_data_source.h"
42#include "content/public/browser/web_ui_message_handler.h"
43#include "google_apis/gaia/gaia_auth_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000044#include "grit/browser_resources.h"
45#include "grit/generated_resources.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000046#include "policy/policy_constants.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000047#include "ui/base/l10n/l10n_util.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010048#include "ui/base/l10n/time_format.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000049
50#if defined(OS_CHROMEOS)
51#include "chrome/browser/chromeos/login/user_manager.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000052#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
53#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
54#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010055#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000056#else
57#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
58#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000059#endif
60
Ben Murdocheb525c52013-07-10 11:40:50 +010061#if !defined(OS_ANDROID) && !defined(OS_IOS)
62#include "chrome/browser/extensions/extension_service.h"
63#include "chrome/browser/extensions/extension_system.h"
64#include "chrome/browser/policy/policy_domain_descriptor.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010065#include "chrome/common/extensions/extension.h"
66#include "chrome/common/extensions/extension_manifest_constants.h"
67#include "chrome/common/extensions/extension_set.h"
68#include "chrome/common/extensions/manifest.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010069#include "chrome/common/policy/policy_schema.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010070#endif
71
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000072namespace em = enterprise_management;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000073
74namespace {
75
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000076content::WebUIDataSource* CreatePolicyUIHTMLSource() {
77 content::WebUIDataSource* source =
78 content::WebUIDataSource::Create(chrome::kChromeUIPolicyHost);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000079
80 // Localized strings.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000081 source->AddLocalizedString("title", IDS_POLICY_TITLE);
82 source->AddLocalizedString("filterPlaceholder",
83 IDS_POLICY_FILTER_PLACEHOLDER);
84 source->AddLocalizedString("reloadPolicies", IDS_POLICY_RELOAD_POLICIES);
85 source->AddLocalizedString("status", IDS_POLICY_STATUS);
86 source->AddLocalizedString("statusDevice", IDS_POLICY_STATUS_DEVICE);
87 source->AddLocalizedString("statusUser", IDS_POLICY_STATUS_USER);
88 source->AddLocalizedString("labelDomain", IDS_POLICY_LABEL_DOMAIN);
89 source->AddLocalizedString("labelUsername", IDS_POLICY_LABEL_USERNAME);
90 source->AddLocalizedString("labelClientId", IDS_POLICY_LABEL_CLIENT_ID);
91 source->AddLocalizedString("labelTimeSinceLastRefresh",
92 IDS_POLICY_LABEL_TIME_SINCE_LAST_REFRESH);
93 source->AddLocalizedString("labelRefreshInterval",
94 IDS_POLICY_LABEL_REFRESH_INTERVAL);
95 source->AddLocalizedString("labelStatus", IDS_POLICY_LABEL_STATUS);
96 source->AddLocalizedString("showUnset", IDS_POLICY_SHOW_UNSET);
97 source->AddLocalizedString("noPoliciesSet", IDS_POLICY_NO_POLICIES_SET);
98 source->AddLocalizedString("headerScope", IDS_POLICY_HEADER_SCOPE);
99 source->AddLocalizedString("headerLevel", IDS_POLICY_HEADER_LEVEL);
100 source->AddLocalizedString("headerName", IDS_POLICY_HEADER_NAME);
101 source->AddLocalizedString("headerValue", IDS_POLICY_HEADER_VALUE);
102 source->AddLocalizedString("headerStatus", IDS_POLICY_HEADER_STATUS);
103 source->AddLocalizedString("showExpandedValue",
104 IDS_POLICY_SHOW_EXPANDED_VALUE);
105 source->AddLocalizedString("hideExpandedValue",
106 IDS_POLICY_HIDE_EXPANDED_VALUE);
107 source->AddLocalizedString("scopeUser", IDS_POLICY_SCOPE_USER);
108 source->AddLocalizedString("scopeDevice", IDS_POLICY_SCOPE_DEVICE);
109 source->AddLocalizedString("levelRecommended", IDS_POLICY_LEVEL_RECOMMENDED);
110 source->AddLocalizedString("levelMandatory", IDS_POLICY_LEVEL_MANDATORY);
111 source->AddLocalizedString("ok", IDS_POLICY_OK);
112 source->AddLocalizedString("unset", IDS_POLICY_UNSET);
113 source->AddLocalizedString("unknown", IDS_POLICY_UNKNOWN);
114
115 source->SetUseJsonJSFormatV2();
116 source->SetJsonPath("strings.js");
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000117
118 // Add required resources.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000119 source->AddResourcePath("policy.css", IDR_POLICY_CSS);
120 source->AddResourcePath("policy.js", IDR_POLICY_JS);
121 source->AddResourcePath("uber_utils.js", IDR_UBER_UTILS_JS);
122 source->SetDefaultResource(IDR_POLICY_HTML);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000123
124 return source;
125}
126
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000127void GetStatusFromCore(const policy::CloudPolicyCore* core,
128 base::DictionaryValue* dict) {
129 const policy::CloudPolicyStore* store = core->store();
130 const policy::CloudPolicyClient* client = core->client();
131 const policy::CloudPolicyRefreshScheduler* refresh_scheduler =
132 core->refresh_scheduler();
133
134 bool no_error = store->status() == policy::CloudPolicyStore::STATUS_OK &&
135 client && client->status() == policy::DM_STATUS_SUCCESS;
136 string16 status = store->status() == policy::CloudPolicyStore::STATUS_OK &&
137 client && client->status() != policy::DM_STATUS_SUCCESS ?
138 policy::FormatDeviceManagementStatus(client->status()) :
139 policy::FormatStoreStatus(store->status(),
140 store->validation_status());
141 const em::PolicyData* policy = store->policy();
142 std::string client_id = policy ? policy->device_id() : std::string();
143 std::string username = policy ? policy->username() : std::string();
144 base::TimeDelta refresh_interval =
145 base::TimeDelta::FromMilliseconds(refresh_scheduler ?
146 refresh_scheduler->refresh_delay() :
147 policy::CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
148 base::Time last_refresh_time = refresh_scheduler ?
149 refresh_scheduler->last_refresh() : base::Time();
150
151 dict->SetBoolean("error", !no_error);
152 dict->SetString("status", status);
153 dict->SetString("clientId", client_id);
154 dict->SetString("username", username);
155 dict->SetString("refreshInterval",
Ben Murdochbb1529c2013-08-08 10:24:53 +0100156 ui::TimeFormat::TimeRemainingShort(refresh_interval));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000157 dict->SetString("timeSinceLastRefresh", last_refresh_time.is_null() ?
158 l10n_util::GetStringUTF16(IDS_POLICY_NEVER_FETCHED) :
Ben Murdochbb1529c2013-08-08 10:24:53 +0100159 ui::TimeFormat::TimeElapsed(base::Time::NowFromSystemTime() -
160 last_refresh_time));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000161}
162
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000163void ExtractDomainFromUsername(base::DictionaryValue* dict) {
164 std::string username;
165 dict->GetString("username", &username);
166 if (!username.empty())
167 dict->SetString("domain", gaia::ExtractDomainName(username));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000168}
169
170} // namespace
171
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000172// An interface for querying the status of cloud policy.
173class CloudPolicyStatusProvider {
174 public:
175 CloudPolicyStatusProvider();
176 virtual ~CloudPolicyStatusProvider();
177
178 // Sets a callback to invoke upon status changes.
179 void SetStatusChangeCallback(const base::Closure& callback);
180
181 virtual void GetStatus(base::DictionaryValue* dict);
182
183 protected:
184 void NotifyStatusChange();
185
186 private:
187 base::Closure callback_;
188
189 DISALLOW_COPY_AND_ASSIGN(CloudPolicyStatusProvider);
190};
191
192// Status provider implementation that pulls cloud policy status from a
193// CloudPolicyCore instance provided at construction time. Also listens for
194// changes on that CloudPolicyCore and reports them through the status change
195// callback.
196class CloudPolicyCoreStatusProvider
197 : public CloudPolicyStatusProvider,
198 public policy::CloudPolicyStore::Observer {
199 public:
200 explicit CloudPolicyCoreStatusProvider(policy::CloudPolicyCore* core);
201 virtual ~CloudPolicyCoreStatusProvider();
202
203 // policy::CloudPolicyStore::Observer implementation.
204 virtual void OnStoreLoaded(policy::CloudPolicyStore* store) OVERRIDE;
205 virtual void OnStoreError(policy::CloudPolicyStore* store) OVERRIDE;
206
207 protected:
208 // Policy status is read from the CloudPolicyClient, CloudPolicyStore and
209 // CloudPolicyRefreshScheduler hosted by this |core_|.
210 policy::CloudPolicyCore* core_;
211
212 DISALLOW_COPY_AND_ASSIGN(CloudPolicyCoreStatusProvider);
213};
214
215// A cloud policy status provider for user policy.
216class UserPolicyStatusProvider : public CloudPolicyCoreStatusProvider {
217 public:
218 explicit UserPolicyStatusProvider(policy::CloudPolicyCore* core);
219 virtual ~UserPolicyStatusProvider();
220
221 // CloudPolicyCoreStatusProvider implementation.
222 virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
223
224 private:
225 DISALLOW_COPY_AND_ASSIGN(UserPolicyStatusProvider);
226};
227
228#if defined(OS_CHROMEOS)
229// A cloud policy status provider for device policy.
230class DevicePolicyStatusProvider : public CloudPolicyCoreStatusProvider {
231 public:
232 explicit DevicePolicyStatusProvider(
233 policy::BrowserPolicyConnector* connector);
234 virtual ~DevicePolicyStatusProvider();
235
236 // CloudPolicyCoreStatusProvider implementation.
237 virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
238
239 private:
240 std::string domain_;
241
242 DISALLOW_COPY_AND_ASSIGN(DevicePolicyStatusProvider);
243};
244
245// A cloud policy status provider that reads policy status from the policy core
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100246// associated with the device-local account specified by |user_id| at
247// construction time. The indirection via user ID and
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000248// DeviceLocalAccountPolicyService is necessary because the device-local account
249// may go away any time behind the scenes, at which point the status message
250// text will indicate CloudPolicyStore::STATUS_BAD_STATE.
251class DeviceLocalAccountPolicyStatusProvider
252 : public CloudPolicyStatusProvider,
253 public policy::DeviceLocalAccountPolicyService::Observer {
254 public:
255 DeviceLocalAccountPolicyStatusProvider(
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100256 const std::string& user_id,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000257 policy::DeviceLocalAccountPolicyService* service);
258 virtual ~DeviceLocalAccountPolicyStatusProvider();
259
260 // CloudPolicyStatusProvider implementation.
261 virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
262
263 // policy::DeviceLocalAccountPolicyService::Observer implementation.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100264 virtual void OnPolicyUpdated(const std::string& user_id) OVERRIDE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000265 virtual void OnDeviceLocalAccountsChanged() OVERRIDE;
266
267 private:
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100268 const std::string user_id_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000269 policy::DeviceLocalAccountPolicyService* service_;
270
271 DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStatusProvider);
272};
273#endif
274
275// The JavaScript message handler for the chrome://policy page.
Ben Murdocheb525c52013-07-10 11:40:50 +0100276class PolicyUIHandler : public content::NotificationObserver,
277 public content::WebUIMessageHandler,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000278 public policy::PolicyService::Observer {
279 public:
280 PolicyUIHandler();
281 virtual ~PolicyUIHandler();
282
Ben Murdocheb525c52013-07-10 11:40:50 +0100283 // content::NotificationObserver implementation.
284 virtual void Observe(int type,
285 const content::NotificationSource& source,
286 const content::NotificationDetails& details) OVERRIDE;
287
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000288 // content::WebUIMessageHandler implementation.
289 virtual void RegisterMessages() OVERRIDE;
290
291 // policy::PolicyService::Observer implementation.
292 virtual void OnPolicyUpdated(const policy::PolicyNamespace& ns,
293 const policy::PolicyMap& previous,
294 const policy::PolicyMap& current) OVERRIDE;
295
296 private:
297 // Send a dictionary containing the names of all known policies to the UI.
298 void SendPolicyNames() const;
299
300 // Send information about the current policy values to the UI. For each policy
301 // whose value has been set, a dictionary containing the value and additional
302 // metadata is sent.
303 void SendPolicyValues() const;
304
305 // Send the status of cloud policy to the UI. For each scope that has cloud
306 // policy enabled (device and/or user), a dictionary containing status
307 // information is sent.
308 void SendStatus() const;
309
Ben Murdocheb525c52013-07-10 11:40:50 +0100310 // Inserts a description of each policy in |policy_map| into |values|, using
311 // the optional errors in |errors| to determine the status of each policy.
312 void GetPolicyValues(const policy::PolicyMap& policy_map,
313 policy::PolicyErrorMap* errors,
314 base::DictionaryValue* values) const;
315
316 void GetChromePolicyValues(base::DictionaryValue* values) const;
317
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000318 void HandleInitialized(const base::ListValue* args);
319 void HandleReloadPolicies(const base::ListValue* args);
320
321 void OnRefreshPoliciesDone() const;
322
323 policy::PolicyService* GetPolicyService() const;
324
325 bool initialized_;
326 std::string device_domain_;
327 base::WeakPtrFactory<PolicyUIHandler> weak_factory_;
328
329 // Providers that supply status dictionaries for user and device policy,
330 // respectively. These are created on initialization time as appropriate for
331 // the platform (Chrome OS / desktop) and type of policy that is in effect.
332 scoped_ptr<CloudPolicyStatusProvider> user_status_provider_;
333 scoped_ptr<CloudPolicyStatusProvider> device_status_provider_;
334
Ben Murdocheb525c52013-07-10 11:40:50 +0100335 content::NotificationRegistrar registrar_;
336
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000337 DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
338};
339
340CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
341}
342
343CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
344}
345
346void CloudPolicyStatusProvider::SetStatusChangeCallback(
347 const base::Closure& callback) {
348 callback_ = callback;
349}
350
351void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
352}
353
354void CloudPolicyStatusProvider::NotifyStatusChange() {
355 if (!callback_.is_null())
356 callback_.Run();
357}
358
359CloudPolicyCoreStatusProvider::CloudPolicyCoreStatusProvider(
360 policy::CloudPolicyCore* core) : core_(core) {
361 core_->store()->AddObserver(this);
362 // TODO(bartfab): Add an observer that watches for client errors. Observing
363 // core_->client() directly is not safe as the client may be destroyed and
364 // (re-)created anytime if the user signs in or out on desktop platforms.
365}
366
367CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
368 core_->store()->RemoveObserver(this);
369}
370
371void CloudPolicyCoreStatusProvider::OnStoreLoaded(
372 policy::CloudPolicyStore* store) {
373 NotifyStatusChange();
374}
375
376void CloudPolicyCoreStatusProvider::OnStoreError(
377 policy::CloudPolicyStore* store) {
378 NotifyStatusChange();
379}
380
381UserPolicyStatusProvider::UserPolicyStatusProvider(
382 policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
383}
384
385UserPolicyStatusProvider::~UserPolicyStatusProvider() {
386}
387
388void UserPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
389 if (!core_->store()->is_managed())
390 return;
391 GetStatusFromCore(core_, dict);
392 ExtractDomainFromUsername(dict);
393}
394
395#if defined(OS_CHROMEOS)
396DevicePolicyStatusProvider::DevicePolicyStatusProvider(
397 policy::BrowserPolicyConnector* connector)
398 : CloudPolicyCoreStatusProvider(
399 connector->GetDeviceCloudPolicyManager()->core()) {
400 domain_ = connector->GetEnterpriseDomain();
401}
402
403DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
404}
405
406void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
407 GetStatusFromCore(core_, dict);
408 dict->SetString("domain", domain_);
409}
410
411DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100412 const std::string& user_id,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000413 policy::DeviceLocalAccountPolicyService* service)
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100414 : user_id_(user_id),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000415 service_(service) {
416 service_->AddObserver(this);
417}
418
419DeviceLocalAccountPolicyStatusProvider::
420 ~DeviceLocalAccountPolicyStatusProvider() {
421 service_->RemoveObserver(this);
422}
423
424void DeviceLocalAccountPolicyStatusProvider::GetStatus(
425 base::DictionaryValue* dict) {
426 const policy::DeviceLocalAccountPolicyBroker* broker =
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100427 service_->GetBrokerForUser(user_id_);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000428 if (broker) {
429 GetStatusFromCore(broker->core(), dict);
430 } else {
431 dict->SetBoolean("error", true);
432 dict->SetString("status",
433 policy::FormatStoreStatus(
434 policy::CloudPolicyStore::STATUS_BAD_STATE,
435 policy::CloudPolicyValidatorBase::VALIDATION_OK));
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100436 dict->SetString("username", std::string());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000437 }
438 ExtractDomainFromUsername(dict);
439 dict->SetBoolean("publicAccount", true);
440}
441
442void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100443 const std::string& user_id) {
444 if (user_id == user_id_)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000445 NotifyStatusChange();
446}
447
448void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
449 NotifyStatusChange();
450}
451#endif
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000452
453PolicyUIHandler::PolicyUIHandler()
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100454 : weak_factory_(this) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000455}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000456
457PolicyUIHandler::~PolicyUIHandler() {
458 GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
Ben Murdocheb525c52013-07-10 11:40:50 +0100459 GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000460}
461
462void PolicyUIHandler::RegisterMessages() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000463#if defined(OS_CHROMEOS)
464 policy::BrowserPolicyConnector* connector =
465 g_browser_process->browser_policy_connector();
466 if (connector->IsEnterpriseManaged())
467 device_status_provider_.reset(new DevicePolicyStatusProvider(connector));
468
469 const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
470 if (user_manager->IsLoggedInAsPublicAccount()) {
471 policy::DeviceLocalAccountPolicyService* local_account_service =
472 connector->GetDeviceLocalAccountPolicyService();
473 if (local_account_service) {
474 user_status_provider_.reset(
475 new DeviceLocalAccountPolicyStatusProvider(
476 user_manager->GetLoggedInUser()->email(), local_account_service));
477 }
478 } else {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100479 policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
480 policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
481 Profile::FromWebUI(web_ui()));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000482 if (user_cloud_policy_manager) {
483 user_status_provider_.reset(
484 new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
485 }
486 }
487#else
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100488 policy::UserCloudPolicyManager* user_cloud_policy_manager =
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000489 policy::UserCloudPolicyManagerFactory::GetForProfile(
490 Profile::FromWebUI(web_ui()));
491 if (user_cloud_policy_manager) {
492 user_status_provider_.reset(
493 new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
494 }
495#endif
496
497 if (!user_status_provider_.get())
498 user_status_provider_.reset(new CloudPolicyStatusProvider());
499 if (!device_status_provider_.get())
500 device_status_provider_.reset(new CloudPolicyStatusProvider());
501
502 base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus,
503 base::Unretained(this)));
504 user_status_provider_->SetStatusChangeCallback(update_callback);
505 device_status_provider_->SetStatusChangeCallback(update_callback);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000506 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
Ben Murdocheb525c52013-07-10 11:40:50 +0100507 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
508
509 registrar_.Add(this,
510 chrome::NOTIFICATION_EXTENSION_LOADED,
511 content::NotificationService::AllSources());
512 registrar_.Add(this,
513 chrome::NOTIFICATION_EXTENSION_UNLOADED,
514 content::NotificationService::AllSources());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000515
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000516 web_ui()->RegisterMessageCallback(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000517 "initialized",
518 base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this)));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000519 web_ui()->RegisterMessageCallback(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000520 "reloadPolicies",
521 base::Bind(&PolicyUIHandler::HandleReloadPolicies,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000522 base::Unretained(this)));
523}
524
Ben Murdocheb525c52013-07-10 11:40:50 +0100525void PolicyUIHandler::Observe(int type,
526 const content::NotificationSource& source,
527 const content::NotificationDetails& details) {
528 DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED ||
529 type == chrome::NOTIFICATION_EXTENSION_UNLOADED);
530 SendPolicyNames();
531 SendPolicyValues();
532}
533
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000534void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000535 const policy::PolicyMap& previous,
536 const policy::PolicyMap& current) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000537 SendPolicyValues();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000538}
539
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000540void PolicyUIHandler::SendPolicyNames() const {
541 base::DictionaryValue names;
Ben Murdocheb525c52013-07-10 11:40:50 +0100542
543 // Add Chrome policy names.
544 base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000545 const policy::PolicyDefinitionList* list =
546 policy::GetChromePolicyDefinitionList();
547 for (const policy::PolicyDefinitionList::Entry* entry = list->begin;
548 entry != list->end; ++entry) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100549 chrome_policy_names->SetBoolean(entry->name, true);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000550 }
Ben Murdocheb525c52013-07-10 11:40:50 +0100551 names.Set("chromePolicyNames", chrome_policy_names);
552
553#if !defined(OS_ANDROID) && !defined(OS_IOS)
554 // Add extension policy names.
555 base::DictionaryValue* extension_policy_names = new base::DictionaryValue;
556 extensions::ExtensionSystem* extension_system =
557 extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
558 const ExtensionSet* extensions =
559 extension_system->extension_service()->extensions();
560 scoped_refptr<const policy::PolicyDomainDescriptor> policy_domain_descriptor;
561 policy_domain_descriptor = GetPolicyService()->
562 GetPolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS);
563 const policy::PolicyDomainDescriptor::SchemaMap& schema_map =
564 policy_domain_descriptor->components();
565
566 for (ExtensionSet::const_iterator it = extensions->begin();
567 it != extensions->end(); ++it) {
568 const extensions::Extension* extension = it->get();
569 // Skip this extension if it's not an enterprise extension.
570 if (!extension->manifest()->HasPath(
571 extension_manifest_keys::kStorageManagedSchema))
572 continue;
573 base::DictionaryValue* extension_value = new base::DictionaryValue;
574 extension_value->SetString("name", extension->name());
575 policy::PolicyDomainDescriptor::SchemaMap::const_iterator schema =
576 schema_map.find(extension->id());
577 base::DictionaryValue* policy_names = new base::DictionaryValue;
578 if (schema != schema_map.end()) {
579 // Get policy names from the extension's policy schema.
580 // Store in a map, not an array, for faster lookup on JS side.
581 const policy::PolicySchemaMap* policies = schema->second->GetProperties();
582 policy::PolicySchemaMap::const_iterator it_policies;
583 for (it_policies = policies->begin(); it_policies != policies->end();
584 it_policies++) {
585 policy_names->SetBoolean(it_policies->first, true);
586 }
587 }
588 extension_value->Set("policyNames", policy_names);
589 extension_policy_names->Set(extension->id(), extension_value);
590 }
591 names.Set("extensionPolicyNames", extension_policy_names);
592#endif
593
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000594 web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
595}
596
597void PolicyUIHandler::SendPolicyValues() const {
Ben Murdocheb525c52013-07-10 11:40:50 +0100598 base::DictionaryValue all_policies;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000599
Ben Murdocheb525c52013-07-10 11:40:50 +0100600 // Add Chrome policy values.
601 base::DictionaryValue* chrome_policies = new base::DictionaryValue;
602 GetChromePolicyValues(chrome_policies);
603 all_policies.Set("chromePolicies", chrome_policies);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000604
Ben Murdocheb525c52013-07-10 11:40:50 +0100605#if !defined(OS_ANDROID) && !defined(OS_IOS)
606 // Add extension policy values.
607 extensions::ExtensionSystem* extension_system =
608 extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
609 const ExtensionSet* extensions =
610 extension_system->extension_service()->extensions();
611 base::DictionaryValue* extension_values = new base::DictionaryValue;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000612
Ben Murdocheb525c52013-07-10 11:40:50 +0100613 for (ExtensionSet::const_iterator it = extensions->begin();
614 it != extensions->end(); ++it) {
615 const extensions::Extension* extension = it->get();
616 // Skip this extension if it's not an enterprise extension.
617 if (!extension->manifest()->HasPath(
618 extension_manifest_keys::kStorageManagedSchema))
619 continue;
620 base::DictionaryValue* extension_policies = new base::DictionaryValue;
621 policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
622 policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
623 policy::PolicyErrorMap empty_error_map;
624 GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
625 &empty_error_map, extension_policies);
626 extension_values->Set(extension->id(), extension_policies);
627 }
628 all_policies.Set("extensionPolicies", extension_values);
629#endif
630 web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
631}
632
633void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
634 policy::PolicyErrorMap* errors,
635 base::DictionaryValue* values) const {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000636 for (policy::PolicyMap::const_iterator entry = map.begin();
Ben Murdocheb525c52013-07-10 11:40:50 +0100637 entry != map.end(); ++entry) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000638 base::DictionaryValue* value = new base::DictionaryValue;
639 value->Set("value", entry->second.value->DeepCopy());
640 if (entry->second.scope == policy::POLICY_SCOPE_USER)
641 value->SetString("scope", "user");
642 else
643 value->SetString("scope", "machine");
644 if (entry->second.level == policy::POLICY_LEVEL_RECOMMENDED)
645 value->SetString("level", "recommended");
646 else
647 value->SetString("level", "mandatory");
Ben Murdocheb525c52013-07-10 11:40:50 +0100648 string16 error = errors->GetErrors(entry->first);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000649 if (!error.empty())
650 value->SetString("error", error);
Ben Murdocheb525c52013-07-10 11:40:50 +0100651 values->Set(entry->first, value);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000652 }
Ben Murdocheb525c52013-07-10 11:40:50 +0100653}
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000654
Ben Murdocheb525c52013-07-10 11:40:50 +0100655void PolicyUIHandler::GetChromePolicyValues(
656 base::DictionaryValue* values) const {
657 policy::PolicyService* policy_service = GetPolicyService();
658 policy::PolicyMap map;
659
660 // Make a copy that can be modified, since some policy values are modified
661 // before being displayed.
662 map.CopyFrom(policy_service->GetPolicies(
663 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
664
665 // Get a list of all the errors in the policy values.
666 const policy::ConfigurationPolicyHandlerList* handler_list =
667 g_browser_process->browser_policy_connector()->GetHandlerList();
668 policy::PolicyErrorMap errors;
669 handler_list->ApplyPolicySettings(map, NULL, &errors);
670
671 // Convert dictionary values to strings for display.
672 handler_list->PrepareForDisplaying(&map);
673
674 GetPolicyValues(map, &errors, values);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000675}
676
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000677void PolicyUIHandler::SendStatus() const {
678 scoped_ptr<base::DictionaryValue> device_status(new base::DictionaryValue);
679 device_status_provider_->GetStatus(device_status.get());
680 if (!device_domain_.empty())
681 device_status->SetString("domain", device_domain_);
682 scoped_ptr<base::DictionaryValue> user_status(new base::DictionaryValue);
683 user_status_provider_->GetStatus(user_status.get());
684 std::string username;
685 user_status->GetString("username", &username);
686 if (!username.empty())
687 user_status->SetString("domain", gaia::ExtractDomainName(username));
688
689 base::DictionaryValue status;
690 if (!device_status->empty())
691 status.Set("device", device_status.release());
692 if (!user_status->empty())
693 status.Set("user", user_status.release());
694
695 web_ui()->CallJavascriptFunction("policy.Page.setStatus", status);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000696}
697
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000698void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
699 SendPolicyNames();
700 SendPolicyValues();
701 SendStatus();
702}
703
704void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000705 GetPolicyService()->RefreshPolicies(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000706 base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000707 weak_factory_.GetWeakPtr()));
708}
709
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000710void PolicyUIHandler::OnRefreshPoliciesDone() const {
711 web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000712}
713
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000714policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100715 return policy::ProfilePolicyConnectorFactory::GetForProfile(
716 Profile::FromWebUI(web_ui()))->policy_service();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000717}
718
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000719PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) {
720 web_ui->AddMessageHandler(new PolicyUIHandler);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000721 content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
722 CreatePolicyUIHTMLSource());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000723}
724
725PolicyUI::~PolicyUI() {
726}