- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / policy_ui.cc
1 // 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
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #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"
14 #include "base/strings/string16.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/policy/browser_policy_connector.h"
20 #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"
27 #include "chrome/browser/policy/configuration_policy_handler_list.h"
28 #include "chrome/browser/policy/policy_error_map.h"
29 #include "chrome/browser/policy/policy_map.h"
30 #include "chrome/browser/policy/policy_service.h"
31 #include "chrome/browser/policy/policy_types.h"
32 #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"
35 #include "chrome/browser/profiles/profile.h"
36 #include "chrome/common/url_constants.h"
37 #include "content/public/browser/notification_observer.h"
38 #include "content/public/browser/notification_registrar.h"
39 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/web_ui.h"
41 #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"
44 #include "grit/browser_resources.h"
45 #include "grit/generated_resources.h"
46 #include "policy/policy_constants.h"
47 #include "ui/base/l10n/l10n_util.h"
48 #include "ui/base/l10n/time_format.h"
49
50 #if defined(OS_CHROMEOS)
51 #include "chrome/browser/chromeos/login/user_manager.h"
52 #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"
55 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
56 #else
57 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
58 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
59 #endif
60
61 #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"
65 #include "chrome/common/extensions/extension.h"
66 #include "chrome/common/extensions/extension_set.h"
67 #include "components/policy/core/common/schema.h"
68 #include "extensions/common/manifest.h"
69 #include "extensions/common/manifest_constants.h"
70 #endif
71
72 namespace em = enterprise_management;
73
74 namespace {
75
76 content::WebUIDataSource* CreatePolicyUIHTMLSource() {
77   content::WebUIDataSource* source =
78       content::WebUIDataSource::Create(chrome::kChromeUIPolicyHost);
79
80   // Localized strings.
81   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");
117
118   // Add required resources.
119   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);
123
124   return source;
125 }
126
127 void 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",
156                   ui::TimeFormat::TimeRemainingShort(refresh_interval));
157   dict->SetString("timeSinceLastRefresh", last_refresh_time.is_null() ?
158       l10n_util::GetStringUTF16(IDS_POLICY_NEVER_FETCHED) :
159       ui::TimeFormat::TimeElapsed(base::Time::NowFromSystemTime() -
160                                   last_refresh_time));
161 }
162
163 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
164   std::string username;
165   dict->GetString("username", &username);
166   if (!username.empty())
167     dict->SetString("domain", gaia::ExtractDomainName(username));
168 }
169
170 }  // namespace
171
172 // An interface for querying the status of cloud policy.
173 class 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.
196 class 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.
216 class 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.
230 class 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
246 // associated with the device-local account specified by |user_id| at
247 // construction time. The indirection via user ID and
248 // 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.
251 class DeviceLocalAccountPolicyStatusProvider
252     : public CloudPolicyStatusProvider,
253       public policy::DeviceLocalAccountPolicyService::Observer {
254  public:
255   DeviceLocalAccountPolicyStatusProvider(
256       const std::string& user_id,
257       policy::DeviceLocalAccountPolicyService* service);
258   virtual ~DeviceLocalAccountPolicyStatusProvider();
259
260   // CloudPolicyStatusProvider implementation.
261   virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
262
263   // policy::DeviceLocalAccountPolicyService::Observer implementation.
264   virtual void OnPolicyUpdated(const std::string& user_id) OVERRIDE;
265   virtual void OnDeviceLocalAccountsChanged() OVERRIDE;
266
267  private:
268   const std::string user_id_;
269   policy::DeviceLocalAccountPolicyService* service_;
270
271   DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStatusProvider);
272 };
273 #endif
274
275 // The JavaScript message handler for the chrome://policy page.
276 class PolicyUIHandler : public content::NotificationObserver,
277                         public content::WebUIMessageHandler,
278                         public policy::PolicyService::Observer {
279  public:
280   PolicyUIHandler();
281   virtual ~PolicyUIHandler();
282
283   // content::NotificationObserver implementation.
284   virtual void Observe(int type,
285                        const content::NotificationSource& source,
286                        const content::NotificationDetails& details) OVERRIDE;
287
288   // 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
310   // 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
318   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
328   // Providers that supply status dictionaries for user and device policy,
329   // respectively. These are created on initialization time as appropriate for
330   // the platform (Chrome OS / desktop) and type of policy that is in effect.
331   scoped_ptr<CloudPolicyStatusProvider> user_status_provider_;
332   scoped_ptr<CloudPolicyStatusProvider> device_status_provider_;
333
334   content::NotificationRegistrar registrar_;
335
336   base::WeakPtrFactory<PolicyUIHandler> weak_factory_;
337
338   DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
339 };
340
341 CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
342 }
343
344 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
345 }
346
347 void CloudPolicyStatusProvider::SetStatusChangeCallback(
348     const base::Closure& callback) {
349   callback_ = callback;
350 }
351
352 void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
353 }
354
355 void CloudPolicyStatusProvider::NotifyStatusChange() {
356   if (!callback_.is_null())
357     callback_.Run();
358 }
359
360 CloudPolicyCoreStatusProvider::CloudPolicyCoreStatusProvider(
361     policy::CloudPolicyCore* core) : core_(core) {
362   core_->store()->AddObserver(this);
363   // TODO(bartfab): Add an observer that watches for client errors. Observing
364   // core_->client() directly is not safe as the client may be destroyed and
365   // (re-)created anytime if the user signs in or out on desktop platforms.
366 }
367
368 CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
369   core_->store()->RemoveObserver(this);
370 }
371
372 void CloudPolicyCoreStatusProvider::OnStoreLoaded(
373     policy::CloudPolicyStore* store) {
374   NotifyStatusChange();
375 }
376
377 void CloudPolicyCoreStatusProvider::OnStoreError(
378     policy::CloudPolicyStore* store) {
379   NotifyStatusChange();
380 }
381
382 UserPolicyStatusProvider::UserPolicyStatusProvider(
383     policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
384 }
385
386 UserPolicyStatusProvider::~UserPolicyStatusProvider() {
387 }
388
389 void UserPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
390   if (!core_->store()->is_managed())
391     return;
392   GetStatusFromCore(core_, dict);
393   ExtractDomainFromUsername(dict);
394 }
395
396 #if defined(OS_CHROMEOS)
397 DevicePolicyStatusProvider::DevicePolicyStatusProvider(
398     policy::BrowserPolicyConnector* connector)
399       : CloudPolicyCoreStatusProvider(
400             connector->GetDeviceCloudPolicyManager()->core()) {
401   domain_ = connector->GetEnterpriseDomain();
402 }
403
404 DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
405 }
406
407 void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
408   GetStatusFromCore(core_, dict);
409   dict->SetString("domain", domain_);
410 }
411
412 DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
413     const std::string& user_id,
414     policy::DeviceLocalAccountPolicyService* service)
415       : user_id_(user_id),
416         service_(service) {
417   service_->AddObserver(this);
418 }
419
420 DeviceLocalAccountPolicyStatusProvider::
421     ~DeviceLocalAccountPolicyStatusProvider() {
422   service_->RemoveObserver(this);
423 }
424
425 void DeviceLocalAccountPolicyStatusProvider::GetStatus(
426     base::DictionaryValue* dict) {
427   const policy::DeviceLocalAccountPolicyBroker* broker =
428       service_->GetBrokerForUser(user_id_);
429   if (broker) {
430     GetStatusFromCore(broker->core(), dict);
431   } else {
432     dict->SetBoolean("error", true);
433     dict->SetString("status",
434                     policy::FormatStoreStatus(
435                         policy::CloudPolicyStore::STATUS_BAD_STATE,
436                         policy::CloudPolicyValidatorBase::VALIDATION_OK));
437     dict->SetString("username", std::string());
438   }
439   ExtractDomainFromUsername(dict);
440   dict->SetBoolean("publicAccount", true);
441 }
442
443 void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
444     const std::string& user_id) {
445   if (user_id == user_id_)
446     NotifyStatusChange();
447 }
448
449 void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
450   NotifyStatusChange();
451 }
452 #endif
453
454 PolicyUIHandler::PolicyUIHandler()
455     : initialized_(false),
456       weak_factory_(this) {
457 }
458
459 PolicyUIHandler::~PolicyUIHandler() {
460   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
461   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
462 }
463
464 void PolicyUIHandler::RegisterMessages() {
465 #if defined(OS_CHROMEOS)
466   policy::BrowserPolicyConnector* connector =
467       g_browser_process->browser_policy_connector();
468   if (connector->IsEnterpriseManaged())
469     device_status_provider_.reset(new DevicePolicyStatusProvider(connector));
470
471   const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
472   if (user_manager->IsLoggedInAsPublicAccount()) {
473     policy::DeviceLocalAccountPolicyService* local_account_service =
474         connector->GetDeviceLocalAccountPolicyService();
475     if (local_account_service) {
476       user_status_provider_.reset(
477           new DeviceLocalAccountPolicyStatusProvider(
478               user_manager->GetLoggedInUser()->email(), local_account_service));
479     }
480   } else {
481     policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
482         policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
483             Profile::FromWebUI(web_ui()));
484     if (user_cloud_policy_manager) {
485       user_status_provider_.reset(
486           new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
487     }
488   }
489 #else
490   policy::UserCloudPolicyManager* user_cloud_policy_manager =
491       policy::UserCloudPolicyManagerFactory::GetForProfile(
492           Profile::FromWebUI(web_ui()));
493   if (user_cloud_policy_manager) {
494     user_status_provider_.reset(
495         new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
496   }
497 #endif
498
499   if (!user_status_provider_.get())
500     user_status_provider_.reset(new CloudPolicyStatusProvider());
501   if (!device_status_provider_.get())
502     device_status_provider_.reset(new CloudPolicyStatusProvider());
503
504   base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus,
505                                            base::Unretained(this)));
506   user_status_provider_->SetStatusChangeCallback(update_callback);
507   device_status_provider_->SetStatusChangeCallback(update_callback);
508   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
509   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
510
511   registrar_.Add(this,
512                  chrome::NOTIFICATION_EXTENSION_LOADED,
513                  content::NotificationService::AllSources());
514   registrar_.Add(this,
515                  chrome::NOTIFICATION_EXTENSION_UNLOADED,
516                  content::NotificationService::AllSources());
517
518   web_ui()->RegisterMessageCallback(
519       "initialized",
520       base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this)));
521   web_ui()->RegisterMessageCallback(
522       "reloadPolicies",
523       base::Bind(&PolicyUIHandler::HandleReloadPolicies,
524                  base::Unretained(this)));
525 }
526
527 void PolicyUIHandler::Observe(int type,
528                               const content::NotificationSource& source,
529                               const content::NotificationDetails& details) {
530   DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED ||
531          type == chrome::NOTIFICATION_EXTENSION_UNLOADED);
532   SendPolicyNames();
533   SendPolicyValues();
534 }
535
536 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
537                                       const policy::PolicyMap& previous,
538                                       const policy::PolicyMap& current) {
539   SendPolicyValues();
540 }
541
542 void PolicyUIHandler::SendPolicyNames() const {
543   base::DictionaryValue names;
544
545   // Add Chrome policy names.
546   base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
547   const policy::PolicyDefinitionList* list =
548       policy::GetChromePolicyDefinitionList();
549   for (const policy::PolicyDefinitionList::Entry* entry = list->begin;
550        entry != list->end; ++entry) {
551     chrome_policy_names->SetBoolean(entry->name, true);
552   }
553   names.Set("chromePolicyNames", chrome_policy_names);
554
555 #if !defined(OS_ANDROID) && !defined(OS_IOS)
556   // Add extension policy names.
557   base::DictionaryValue* extension_policy_names = new base::DictionaryValue;
558   extensions::ExtensionSystem* extension_system =
559       extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
560   const ExtensionSet* extensions =
561       extension_system->extension_service()->extensions();
562   scoped_refptr<const policy::PolicyDomainDescriptor> policy_domain_descriptor;
563   policy_domain_descriptor = GetPolicyService()->
564       GetPolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS);
565   const policy::PolicyDomainDescriptor::SchemaMap& schema_map =
566       policy_domain_descriptor->components();
567
568   for (ExtensionSet::const_iterator it = extensions->begin();
569        it != extensions->end(); ++it) {
570     const extensions::Extension* extension = it->get();
571     // Skip this extension if it's not an enterprise extension.
572     if (!extension->manifest()->HasPath(
573         extensions::manifest_keys::kStorageManagedSchema))
574       continue;
575     base::DictionaryValue* extension_value = new base::DictionaryValue;
576     extension_value->SetString("name", extension->name());
577     policy::PolicyDomainDescriptor::SchemaMap::const_iterator schema =
578         schema_map.find(extension->id());
579     base::DictionaryValue* policy_names = new base::DictionaryValue;
580     if (schema != schema_map.end()) {
581       // Get policy names from the extension's policy schema.
582       // Store in a map, not an array, for faster lookup on JS side.
583       policy::Schema policy_schema = schema->second;
584       for (policy::Schema::Iterator it_policies =
585                policy_schema.GetPropertiesIterator();
586            !it_policies.IsAtEnd(); it_policies.Advance()) {
587         policy_names->SetBoolean(it_policies.key(), true);
588       }
589     }
590     extension_value->Set("policyNames", policy_names);
591     extension_policy_names->Set(extension->id(), extension_value);
592   }
593   names.Set("extensionPolicyNames", extension_policy_names);
594 #endif
595
596   web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
597 }
598
599 void PolicyUIHandler::SendPolicyValues() const {
600   base::DictionaryValue all_policies;
601
602   // Add Chrome policy values.
603   base::DictionaryValue* chrome_policies = new base::DictionaryValue;
604   GetChromePolicyValues(chrome_policies);
605   all_policies.Set("chromePolicies", chrome_policies);
606
607 #if !defined(OS_ANDROID) && !defined(OS_IOS)
608   // Add extension policy values.
609   extensions::ExtensionSystem* extension_system =
610       extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
611   const ExtensionSet* extensions =
612       extension_system->extension_service()->extensions();
613   base::DictionaryValue* extension_values = new base::DictionaryValue;
614
615   for (ExtensionSet::const_iterator it = extensions->begin();
616        it != extensions->end(); ++it) {
617     const extensions::Extension* extension = it->get();
618     // Skip this extension if it's not an enterprise extension.
619     if (!extension->manifest()->HasPath(
620         extensions::manifest_keys::kStorageManagedSchema))
621       continue;
622     base::DictionaryValue* extension_policies = new base::DictionaryValue;
623     policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
624         policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
625     policy::PolicyErrorMap empty_error_map;
626     GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
627                     &empty_error_map, extension_policies);
628     extension_values->Set(extension->id(), extension_policies);
629   }
630   all_policies.Set("extensionPolicies", extension_values);
631 #endif
632   web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
633 }
634
635 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
636                                       policy::PolicyErrorMap* errors,
637                                       base::DictionaryValue* values) const {
638   for (policy::PolicyMap::const_iterator entry = map.begin();
639        entry != map.end(); ++entry) {
640     base::DictionaryValue* value = new base::DictionaryValue;
641     value->Set("value", entry->second.value->DeepCopy());
642     if (entry->second.scope == policy::POLICY_SCOPE_USER)
643       value->SetString("scope", "user");
644     else
645       value->SetString("scope", "machine");
646     if (entry->second.level == policy::POLICY_LEVEL_RECOMMENDED)
647       value->SetString("level", "recommended");
648     else
649       value->SetString("level", "mandatory");
650     string16 error = errors->GetErrors(entry->first);
651     if (!error.empty())
652       value->SetString("error", error);
653     values->Set(entry->first, value);
654   }
655 }
656
657 void PolicyUIHandler::GetChromePolicyValues(
658     base::DictionaryValue* values) const {
659   policy::PolicyService* policy_service = GetPolicyService();
660   policy::PolicyMap map;
661
662   // Make a copy that can be modified, since some policy values are modified
663   // before being displayed.
664   map.CopyFrom(policy_service->GetPolicies(
665       policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
666
667   // Get a list of all the errors in the policy values.
668   const policy::ConfigurationPolicyHandlerList* handler_list =
669       g_browser_process->browser_policy_connector()->GetHandlerList();
670   policy::PolicyErrorMap errors;
671   handler_list->ApplyPolicySettings(map, NULL, &errors);
672
673   // Convert dictionary values to strings for display.
674   handler_list->PrepareForDisplaying(&map);
675
676   GetPolicyValues(map, &errors, values);
677 }
678
679 void PolicyUIHandler::SendStatus() const {
680   scoped_ptr<base::DictionaryValue> device_status(new base::DictionaryValue);
681   device_status_provider_->GetStatus(device_status.get());
682   if (!device_domain_.empty())
683     device_status->SetString("domain", device_domain_);
684   scoped_ptr<base::DictionaryValue> user_status(new base::DictionaryValue);
685   user_status_provider_->GetStatus(user_status.get());
686   std::string username;
687   user_status->GetString("username", &username);
688   if (!username.empty())
689     user_status->SetString("domain", gaia::ExtractDomainName(username));
690
691   base::DictionaryValue status;
692   if (!device_status->empty())
693     status.Set("device", device_status.release());
694   if (!user_status->empty())
695     status.Set("user", user_status.release());
696
697   web_ui()->CallJavascriptFunction("policy.Page.setStatus", status);
698 }
699
700 void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
701   SendPolicyNames();
702   SendPolicyValues();
703   SendStatus();
704 }
705
706 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
707   GetPolicyService()->RefreshPolicies(
708       base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
709                  weak_factory_.GetWeakPtr()));
710 }
711
712 void PolicyUIHandler::OnRefreshPoliciesDone() const {
713   web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
714 }
715
716 policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
717   return policy::ProfilePolicyConnectorFactory::GetForProfile(
718       Profile::FromWebUI(web_ui()))->policy_service();
719 }
720
721 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) {
722   web_ui->AddMessageHandler(new PolicyUIHandler);
723   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
724                                 CreatePolicyUIHTMLSource());
725 }
726
727 PolicyUI::~PolicyUI() {
728 }