Update To 11.40.268.0
[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/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/strings/string16.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/policy/profile_policy_connector.h"
21 #include "chrome/browser/policy/profile_policy_connector_factory.h"
22 #include "chrome/browser/policy/schema_registry_service.h"
23 #include "chrome/browser/policy/schema_registry_service_factory.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/common/url_constants.h"
26 #include "components/policy/core/browser/browser_policy_connector.h"
27 #include "components/policy/core/browser/cloud/message_util.h"
28 #include "components/policy/core/browser/configuration_policy_handler_list.h"
29 #include "components/policy/core/browser/policy_error_map.h"
30 #include "components/policy/core/common/cloud/cloud_policy_client.h"
31 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
32 #include "components/policy/core/common/cloud/cloud_policy_core.h"
33 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
34 #include "components/policy/core/common/cloud/cloud_policy_store.h"
35 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
36 #include "components/policy/core/common/policy_map.h"
37 #include "components/policy/core/common/policy_namespace.h"
38 #include "components/policy/core/common/policy_service.h"
39 #include "components/policy/core/common/policy_types.h"
40 #include "components/policy/core/common/schema.h"
41 #include "components/policy/core/common/schema_map.h"
42 #include "components/policy/core/common/schema_registry.h"
43 #include "content/public/browser/notification_observer.h"
44 #include "content/public/browser/notification_registrar.h"
45 #include "content/public/browser/notification_service.h"
46 #include "content/public/browser/web_ui.h"
47 #include "content/public/browser/web_ui_data_source.h"
48 #include "content/public/browser/web_ui_message_handler.h"
49 #include "google_apis/gaia/gaia_auth_util.h"
50 #include "grit/browser_resources.h"
51 #include "grit/components_strings.h"
52 #include "policy/policy_constants.h"
53 #include "policy/proto/device_management_backend.pb.h"
54 #include "ui/base/l10n/l10n_util.h"
55 #include "ui/base/l10n/time_format.h"
56
57 #if defined(OS_CHROMEOS)
58 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
59 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
60 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
61 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
62 #include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
63 #include "components/user_manager/user_manager.h"
64 #else
65 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
66 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
67 #include "content/public/browser/web_contents.h"
68 #endif
69
70 #if !defined(OS_ANDROID) && !defined(OS_IOS)
71 #include "chrome/browser/extensions/extension_service.h"
72 #include "extensions/browser/extension_system.h"
73 #include "extensions/common/extension.h"
74 #include "extensions/common/extension_set.h"
75 #include "extensions/common/manifest.h"
76 #include "extensions/common/manifest_constants.h"
77 #endif
78
79 namespace em = enterprise_management;
80
81 namespace {
82
83 content::WebUIDataSource* CreatePolicyUIHTMLSource() {
84   content::WebUIDataSource* source =
85       content::WebUIDataSource::Create(chrome::kChromeUIPolicyHost);
86
87   // Localized strings.
88   source->AddLocalizedString("title", IDS_POLICY_TITLE);
89   source->AddLocalizedString("filterPlaceholder",
90                              IDS_POLICY_FILTER_PLACEHOLDER);
91   source->AddLocalizedString("reloadPolicies", IDS_POLICY_RELOAD_POLICIES);
92   source->AddLocalizedString("status", IDS_POLICY_STATUS);
93   source->AddLocalizedString("statusDevice", IDS_POLICY_STATUS_DEVICE);
94   source->AddLocalizedString("statusUser", IDS_POLICY_STATUS_USER);
95   source->AddLocalizedString("labelDomain", IDS_POLICY_LABEL_DOMAIN);
96   source->AddLocalizedString("labelUsername", IDS_POLICY_LABEL_USERNAME);
97   source->AddLocalizedString("labelClientId", IDS_POLICY_LABEL_CLIENT_ID);
98   source->AddLocalizedString("labelTimeSinceLastRefresh",
99                              IDS_POLICY_LABEL_TIME_SINCE_LAST_REFRESH);
100   source->AddLocalizedString("labelRefreshInterval",
101                              IDS_POLICY_LABEL_REFRESH_INTERVAL);
102   source->AddLocalizedString("labelStatus", IDS_POLICY_LABEL_STATUS);
103   source->AddLocalizedString("showUnset", IDS_POLICY_SHOW_UNSET);
104   source->AddLocalizedString("noPoliciesSet", IDS_POLICY_NO_POLICIES_SET);
105   source->AddLocalizedString("headerScope", IDS_POLICY_HEADER_SCOPE);
106   source->AddLocalizedString("headerLevel", IDS_POLICY_HEADER_LEVEL);
107   source->AddLocalizedString("headerName", IDS_POLICY_HEADER_NAME);
108   source->AddLocalizedString("headerValue", IDS_POLICY_HEADER_VALUE);
109   source->AddLocalizedString("headerStatus", IDS_POLICY_HEADER_STATUS);
110   source->AddLocalizedString("showExpandedValue",
111                              IDS_POLICY_SHOW_EXPANDED_VALUE);
112   source->AddLocalizedString("hideExpandedValue",
113                              IDS_POLICY_HIDE_EXPANDED_VALUE);
114   source->AddLocalizedString("scopeUser", IDS_POLICY_SCOPE_USER);
115   source->AddLocalizedString("scopeDevice", IDS_POLICY_SCOPE_DEVICE);
116   source->AddLocalizedString("levelRecommended", IDS_POLICY_LEVEL_RECOMMENDED);
117   source->AddLocalizedString("levelMandatory", IDS_POLICY_LEVEL_MANDATORY);
118   source->AddLocalizedString("ok", IDS_POLICY_OK);
119   source->AddLocalizedString("unset", IDS_POLICY_UNSET);
120   source->AddLocalizedString("unknown", IDS_POLICY_UNKNOWN);
121
122   source->SetJsonPath("strings.js");
123
124   // Add required resources.
125   source->AddResourcePath("policy.css", IDR_POLICY_CSS);
126   source->AddResourcePath("policy.js", IDR_POLICY_JS);
127   source->AddResourcePath("uber_utils.js", IDR_UBER_UTILS_JS);
128   source->SetDefaultResource(IDR_POLICY_HTML);
129
130   return source;
131 }
132
133 // Formats the association state indicated by |data|. If |data| is NULL, the
134 // state is considered to be UNMANAGED.
135 base::string16 FormatAssociationState(const em::PolicyData* data) {
136   if (data) {
137     switch (data->state()) {
138       case em::PolicyData::ACTIVE:
139         return l10n_util::GetStringUTF16(IDS_POLICY_ASSOCIATION_STATE_ACTIVE);
140       case em::PolicyData::UNMANAGED:
141         return l10n_util::GetStringUTF16(
142             IDS_POLICY_ASSOCIATION_STATE_UNMANAGED);
143       case em::PolicyData::DEPROVISIONED:
144         return l10n_util::GetStringUTF16(
145             IDS_POLICY_ASSOCIATION_STATE_DEPROVISIONED);
146     }
147     NOTREACHED() << "Unknown state " << data->state();
148   }
149
150   // Default to UNMANAGED for the case of missing policy or bad state enum.
151   return l10n_util::GetStringUTF16(IDS_POLICY_ASSOCIATION_STATE_UNMANAGED);
152 }
153
154 void GetStatusFromCore(const policy::CloudPolicyCore* core,
155                        base::DictionaryValue* dict) {
156   const policy::CloudPolicyStore* store = core->store();
157   const policy::CloudPolicyClient* client = core->client();
158   const policy::CloudPolicyRefreshScheduler* refresh_scheduler =
159         core->refresh_scheduler();
160
161   // CloudPolicyStore errors take precedence to show in the status message.
162   // Other errors (such as transient policy fetching problems) get displayed
163   // only if CloudPolicyStore is in STATUS_OK.
164   base::string16 status =
165       policy::FormatStoreStatus(store->status(), store->validation_status());
166   if (store->status() == policy::CloudPolicyStore::STATUS_OK) {
167     if (client && client->status() != policy::DM_STATUS_SUCCESS)
168       status = policy::FormatDeviceManagementStatus(client->status());
169     else if (!store->is_managed())
170       status = FormatAssociationState(store->policy());
171   }
172
173   const em::PolicyData* policy = store->policy();
174   std::string client_id = policy ? policy->device_id() : std::string();
175   std::string username = policy ? policy->username() : std::string();
176   base::TimeDelta refresh_interval =
177       base::TimeDelta::FromMilliseconds(refresh_scheduler ?
178           refresh_scheduler->refresh_delay() :
179           policy::CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
180   base::Time last_refresh_time = refresh_scheduler ?
181       refresh_scheduler->last_refresh() : base::Time();
182
183   bool no_error = store->status() == policy::CloudPolicyStore::STATUS_OK &&
184                   client && client->status() == policy::DM_STATUS_SUCCESS;
185   dict->SetBoolean("error", !no_error);
186   dict->SetString("status", status);
187   dict->SetString("clientId", client_id);
188   dict->SetString("username", username);
189   dict->SetString("refreshInterval",
190                   ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
191                                          ui::TimeFormat::LENGTH_SHORT,
192                                          refresh_interval));
193   dict->SetString("timeSinceLastRefresh", last_refresh_time.is_null() ?
194       l10n_util::GetStringUTF16(IDS_POLICY_NEVER_FETCHED) :
195       ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
196                              ui::TimeFormat::LENGTH_SHORT,
197                              base::Time::NowFromSystemTime() -
198                                  last_refresh_time));
199 }
200
201 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
202   std::string username;
203   dict->GetString("username", &username);
204   if (!username.empty())
205     dict->SetString("domain", gaia::ExtractDomainName(username));
206 }
207
208 // Utility function that returns a JSON serialization of the given |dict|.
209 scoped_ptr<base::StringValue> DictionaryToJSONString(
210     const base::DictionaryValue* dict) {
211   std::string json_string;
212   base::JSONWriter::WriteWithOptions(dict,
213                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
214                                      &json_string);
215   return make_scoped_ptr(new base::StringValue(json_string));
216 }
217
218 // Returns a copy of |value| with some values converted to a representation that
219 // i18n_template.js will display in a nicer way.
220 scoped_ptr<base::Value> CopyAndConvert(const base::Value* value) {
221   const base::DictionaryValue* dict = NULL;
222   if (value->GetAsDictionary(&dict))
223     return DictionaryToJSONString(dict);
224
225   scoped_ptr<base::Value> copy(value->DeepCopy());
226   base::ListValue* list = NULL;
227   if (copy->GetAsList(&list)) {
228     for (size_t i = 0; i < list->GetSize(); ++i) {
229       if (list->GetDictionary(i, &dict))
230         list->Set(i, DictionaryToJSONString(dict).release());
231     }
232   }
233
234   return copy.Pass();
235 }
236
237 }  // namespace
238
239 // An interface for querying the status of cloud policy.
240 class CloudPolicyStatusProvider {
241  public:
242   CloudPolicyStatusProvider();
243   virtual ~CloudPolicyStatusProvider();
244
245   // Sets a callback to invoke upon status changes.
246   void SetStatusChangeCallback(const base::Closure& callback);
247
248   virtual void GetStatus(base::DictionaryValue* dict);
249
250  protected:
251   void NotifyStatusChange();
252
253  private:
254   base::Closure callback_;
255
256   DISALLOW_COPY_AND_ASSIGN(CloudPolicyStatusProvider);
257 };
258
259 // Status provider implementation that pulls cloud policy status from a
260 // CloudPolicyCore instance provided at construction time. Also listens for
261 // changes on that CloudPolicyCore and reports them through the status change
262 // callback.
263 class CloudPolicyCoreStatusProvider
264     : public CloudPolicyStatusProvider,
265       public policy::CloudPolicyStore::Observer {
266  public:
267   explicit CloudPolicyCoreStatusProvider(policy::CloudPolicyCore* core);
268   ~CloudPolicyCoreStatusProvider() override;
269
270   // policy::CloudPolicyStore::Observer implementation.
271   void OnStoreLoaded(policy::CloudPolicyStore* store) override;
272   void OnStoreError(policy::CloudPolicyStore* store) override;
273
274  protected:
275   // Policy status is read from the CloudPolicyClient, CloudPolicyStore and
276   // CloudPolicyRefreshScheduler hosted by this |core_|.
277   policy::CloudPolicyCore* core_;
278
279  private:
280   DISALLOW_COPY_AND_ASSIGN(CloudPolicyCoreStatusProvider);
281 };
282
283 // A cloud policy status provider for user policy.
284 class UserPolicyStatusProvider : public CloudPolicyCoreStatusProvider {
285  public:
286   explicit UserPolicyStatusProvider(policy::CloudPolicyCore* core);
287   ~UserPolicyStatusProvider() override;
288
289   // CloudPolicyCoreStatusProvider implementation.
290   void GetStatus(base::DictionaryValue* dict) override;
291
292  private:
293   DISALLOW_COPY_AND_ASSIGN(UserPolicyStatusProvider);
294 };
295
296 #if defined(OS_CHROMEOS)
297 // A cloud policy status provider for device policy.
298 class DevicePolicyStatusProvider : public CloudPolicyCoreStatusProvider {
299  public:
300   explicit DevicePolicyStatusProvider(
301       policy::BrowserPolicyConnectorChromeOS* connector);
302   virtual ~DevicePolicyStatusProvider();
303
304   // CloudPolicyCoreStatusProvider implementation.
305   virtual void GetStatus(base::DictionaryValue* dict) override;
306
307  private:
308   std::string domain_;
309
310   DISALLOW_COPY_AND_ASSIGN(DevicePolicyStatusProvider);
311 };
312
313 // A cloud policy status provider that reads policy status from the policy core
314 // associated with the device-local account specified by |user_id| at
315 // construction time. The indirection via user ID and
316 // DeviceLocalAccountPolicyService is necessary because the device-local account
317 // may go away any time behind the scenes, at which point the status message
318 // text will indicate CloudPolicyStore::STATUS_BAD_STATE.
319 class DeviceLocalAccountPolicyStatusProvider
320     : public CloudPolicyStatusProvider,
321       public policy::DeviceLocalAccountPolicyService::Observer {
322  public:
323   DeviceLocalAccountPolicyStatusProvider(
324       const std::string& user_id,
325       policy::DeviceLocalAccountPolicyService* service);
326   virtual ~DeviceLocalAccountPolicyStatusProvider();
327
328   // CloudPolicyStatusProvider implementation.
329   virtual void GetStatus(base::DictionaryValue* dict) override;
330
331   // policy::DeviceLocalAccountPolicyService::Observer implementation.
332   virtual void OnPolicyUpdated(const std::string& user_id) override;
333   virtual void OnDeviceLocalAccountsChanged() override;
334
335  private:
336   const std::string user_id_;
337   policy::DeviceLocalAccountPolicyService* service_;
338
339   DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStatusProvider);
340 };
341 #endif
342
343 // The JavaScript message handler for the chrome://policy page.
344 class PolicyUIHandler : public content::NotificationObserver,
345                         public content::WebUIMessageHandler,
346                         public policy::PolicyService::Observer {
347  public:
348   PolicyUIHandler();
349   ~PolicyUIHandler() override;
350
351   // content::NotificationObserver implementation.
352   void Observe(int type,
353                const content::NotificationSource& source,
354                const content::NotificationDetails& details) override;
355
356   // content::WebUIMessageHandler implementation.
357   void RegisterMessages() override;
358
359   // policy::PolicyService::Observer implementation.
360   void OnPolicyUpdated(const policy::PolicyNamespace& ns,
361                        const policy::PolicyMap& previous,
362                        const policy::PolicyMap& current) override;
363
364  private:
365   // Send a dictionary containing the names of all known policies to the UI.
366   void SendPolicyNames() const;
367
368   // Send information about the current policy values to the UI. For each policy
369   // whose value has been set, a dictionary containing the value and additional
370   // metadata is sent.
371   void SendPolicyValues() const;
372
373   // Send the status of cloud policy to the UI. For each scope that has cloud
374   // policy enabled (device and/or user), a dictionary containing status
375   // information is sent.
376   void SendStatus() const;
377
378   // Inserts a description of each policy in |policy_map| into |values|, using
379   // the optional errors in |errors| to determine the status of each policy.
380   void GetPolicyValues(const policy::PolicyMap& policy_map,
381                        policy::PolicyErrorMap* errors,
382                        base::DictionaryValue* values) const;
383
384   void GetChromePolicyValues(base::DictionaryValue* values) const;
385
386   void HandleInitialized(const base::ListValue* args);
387   void HandleReloadPolicies(const base::ListValue* args);
388
389   void OnRefreshPoliciesDone() const;
390
391   policy::PolicyService* GetPolicyService() const;
392
393   bool initialized_;
394   std::string device_domain_;
395
396   // Providers that supply status dictionaries for user and device policy,
397   // respectively. These are created on initialization time as appropriate for
398   // the platform (Chrome OS / desktop) and type of policy that is in effect.
399   scoped_ptr<CloudPolicyStatusProvider> user_status_provider_;
400   scoped_ptr<CloudPolicyStatusProvider> device_status_provider_;
401
402 #if defined(ENABLE_EXTENSIONS)
403   content::NotificationRegistrar registrar_;
404 #endif
405
406   base::WeakPtrFactory<PolicyUIHandler> weak_factory_;
407
408   DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
409 };
410
411 CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
412 }
413
414 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
415 }
416
417 void CloudPolicyStatusProvider::SetStatusChangeCallback(
418     const base::Closure& callback) {
419   callback_ = callback;
420 }
421
422 void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
423 }
424
425 void CloudPolicyStatusProvider::NotifyStatusChange() {
426   if (!callback_.is_null())
427     callback_.Run();
428 }
429
430 CloudPolicyCoreStatusProvider::CloudPolicyCoreStatusProvider(
431     policy::CloudPolicyCore* core) : core_(core) {
432   core_->store()->AddObserver(this);
433   // TODO(bartfab): Add an observer that watches for client errors. Observing
434   // core_->client() directly is not safe as the client may be destroyed and
435   // (re-)created anytime if the user signs in or out on desktop platforms.
436 }
437
438 CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
439   core_->store()->RemoveObserver(this);
440 }
441
442 void CloudPolicyCoreStatusProvider::OnStoreLoaded(
443     policy::CloudPolicyStore* store) {
444   NotifyStatusChange();
445 }
446
447 void CloudPolicyCoreStatusProvider::OnStoreError(
448     policy::CloudPolicyStore* store) {
449   NotifyStatusChange();
450 }
451
452 UserPolicyStatusProvider::UserPolicyStatusProvider(
453     policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
454 }
455
456 UserPolicyStatusProvider::~UserPolicyStatusProvider() {
457 }
458
459 void UserPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
460   if (!core_->store()->is_managed())
461     return;
462   GetStatusFromCore(core_, dict);
463   ExtractDomainFromUsername(dict);
464 }
465
466 #if defined(OS_CHROMEOS)
467 DevicePolicyStatusProvider::DevicePolicyStatusProvider(
468     policy::BrowserPolicyConnectorChromeOS* connector)
469       : CloudPolicyCoreStatusProvider(
470             connector->GetDeviceCloudPolicyManager()->core()) {
471   domain_ = connector->GetEnterpriseDomain();
472 }
473
474 DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
475 }
476
477 void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
478   GetStatusFromCore(core_, dict);
479   dict->SetString("domain", domain_);
480 }
481
482 DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
483     const std::string& user_id,
484     policy::DeviceLocalAccountPolicyService* service)
485       : user_id_(user_id),
486         service_(service) {
487   service_->AddObserver(this);
488 }
489
490 DeviceLocalAccountPolicyStatusProvider::
491     ~DeviceLocalAccountPolicyStatusProvider() {
492   service_->RemoveObserver(this);
493 }
494
495 void DeviceLocalAccountPolicyStatusProvider::GetStatus(
496     base::DictionaryValue* dict) {
497   const policy::DeviceLocalAccountPolicyBroker* broker =
498       service_->GetBrokerForUser(user_id_);
499   if (broker) {
500     GetStatusFromCore(broker->core(), dict);
501   } else {
502     dict->SetBoolean("error", true);
503     dict->SetString("status",
504                     policy::FormatStoreStatus(
505                         policy::CloudPolicyStore::STATUS_BAD_STATE,
506                         policy::CloudPolicyValidatorBase::VALIDATION_OK));
507     dict->SetString("username", std::string());
508   }
509   ExtractDomainFromUsername(dict);
510   dict->SetBoolean("publicAccount", true);
511 }
512
513 void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
514     const std::string& user_id) {
515   if (user_id == user_id_)
516     NotifyStatusChange();
517 }
518
519 void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
520   NotifyStatusChange();
521 }
522 #endif
523
524 PolicyUIHandler::PolicyUIHandler()
525     : initialized_(false),
526       weak_factory_(this) {
527 }
528
529 PolicyUIHandler::~PolicyUIHandler() {
530   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
531   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
532 }
533
534 void PolicyUIHandler::RegisterMessages() {
535 #if defined(OS_CHROMEOS)
536   policy::BrowserPolicyConnectorChromeOS* connector =
537       g_browser_process->platform_part()->browser_policy_connector_chromeos();
538   if (connector->IsEnterpriseManaged())
539     device_status_provider_.reset(new DevicePolicyStatusProvider(connector));
540
541   const user_manager::UserManager* user_manager =
542       user_manager::UserManager::Get();
543   if (user_manager->IsLoggedInAsPublicAccount()) {
544     policy::DeviceLocalAccountPolicyService* local_account_service =
545         connector->GetDeviceLocalAccountPolicyService();
546     if (local_account_service) {
547       user_status_provider_.reset(
548           new DeviceLocalAccountPolicyStatusProvider(
549               user_manager->GetLoggedInUser()->email(), local_account_service));
550     }
551   } else {
552     policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
553         policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
554             Profile::FromWebUI(web_ui()));
555     if (user_cloud_policy_manager) {
556       user_status_provider_.reset(
557           new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
558     }
559   }
560 #else
561   policy::UserCloudPolicyManager* user_cloud_policy_manager =
562       policy::UserCloudPolicyManagerFactory::GetForBrowserContext(
563           web_ui()->GetWebContents()->GetBrowserContext());
564   if (user_cloud_policy_manager) {
565     user_status_provider_.reset(
566         new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
567   }
568 #endif
569
570   if (!user_status_provider_.get())
571     user_status_provider_.reset(new CloudPolicyStatusProvider());
572   if (!device_status_provider_.get())
573     device_status_provider_.reset(new CloudPolicyStatusProvider());
574
575   base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus,
576                                            base::Unretained(this)));
577   user_status_provider_->SetStatusChangeCallback(update_callback);
578   device_status_provider_->SetStatusChangeCallback(update_callback);
579   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
580   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
581
582 #if defined(ENABLE_EXTENSIONS)
583   registrar_.Add(this,
584                  extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
585                  content::NotificationService::AllSources());
586   registrar_.Add(this,
587                  extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
588                  content::NotificationService::AllSources());
589 #endif
590
591   web_ui()->RegisterMessageCallback(
592       "initialized",
593       base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this)));
594   web_ui()->RegisterMessageCallback(
595       "reloadPolicies",
596       base::Bind(&PolicyUIHandler::HandleReloadPolicies,
597                  base::Unretained(this)));
598 }
599
600 void PolicyUIHandler::Observe(int type,
601                               const content::NotificationSource& source,
602                               const content::NotificationDetails& details) {
603 #if defined(ENABLE_EXTENSIONS)
604   DCHECK(type == extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED ||
605          type == extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED);
606   SendPolicyNames();
607   SendPolicyValues();
608 #endif
609 }
610
611 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
612                                       const policy::PolicyMap& previous,
613                                       const policy::PolicyMap& current) {
614   SendPolicyValues();
615 }
616
617 void PolicyUIHandler::SendPolicyNames() const {
618   base::DictionaryValue names;
619
620   Profile* profile = Profile::FromWebUI(web_ui());
621   policy::SchemaRegistry* registry =
622       policy::SchemaRegistryServiceFactory::GetForContext(
623           profile->GetOriginalProfile())->registry();
624   scoped_refptr<policy::SchemaMap> schema_map = registry->schema_map();
625
626   // Add Chrome policy names.
627   base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
628   policy::PolicyNamespace chrome_ns(policy::POLICY_DOMAIN_CHROME, "");
629   const policy::Schema* chrome_schema = schema_map->GetSchema(chrome_ns);
630   for (policy::Schema::Iterator it = chrome_schema->GetPropertiesIterator();
631        !it.IsAtEnd(); it.Advance()) {
632     chrome_policy_names->SetBoolean(it.key(), true);
633   }
634   names.Set("chromePolicyNames", chrome_policy_names);
635
636 #if !defined(OS_ANDROID) && !defined(OS_IOS)
637   // Add extension policy names.
638   base::DictionaryValue* extension_policy_names = new base::DictionaryValue;
639
640   extensions::ExtensionSystem* extension_system =
641       extensions::ExtensionSystem::Get(profile);
642   const extensions::ExtensionSet* extensions =
643       extension_system->extension_service()->extensions();
644
645   for (extensions::ExtensionSet::const_iterator it = extensions->begin();
646        it != extensions->end(); ++it) {
647     const extensions::Extension* extension = it->get();
648     // Skip this extension if it's not an enterprise extension.
649     if (!extension->manifest()->HasPath(
650         extensions::manifest_keys::kStorageManagedSchema))
651       continue;
652     base::DictionaryValue* extension_value = new base::DictionaryValue;
653     extension_value->SetString("name", extension->name());
654     const policy::Schema* schema =
655         schema_map->GetSchema(policy::PolicyNamespace(
656             policy::POLICY_DOMAIN_EXTENSIONS, extension->id()));
657     base::DictionaryValue* policy_names = new base::DictionaryValue;
658     if (schema && schema->valid()) {
659       // Get policy names from the extension's policy schema.
660       // Store in a map, not an array, for faster lookup on JS side.
661       for (policy::Schema::Iterator prop = schema->GetPropertiesIterator();
662            !prop.IsAtEnd(); prop.Advance()) {
663         policy_names->SetBoolean(prop.key(), true);
664       }
665     }
666     extension_value->Set("policyNames", policy_names);
667     extension_policy_names->Set(extension->id(), extension_value);
668   }
669   names.Set("extensionPolicyNames", extension_policy_names);
670 #endif
671
672   web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
673 }
674
675 void PolicyUIHandler::SendPolicyValues() const {
676   base::DictionaryValue all_policies;
677
678   // Add Chrome policy values.
679   base::DictionaryValue* chrome_policies = new base::DictionaryValue;
680   GetChromePolicyValues(chrome_policies);
681   all_policies.Set("chromePolicies", chrome_policies);
682
683 #if !defined(OS_ANDROID) && !defined(OS_IOS)
684   // Add extension policy values.
685   extensions::ExtensionSystem* extension_system =
686       extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
687   const extensions::ExtensionSet* extensions =
688       extension_system->extension_service()->extensions();
689   base::DictionaryValue* extension_values = new base::DictionaryValue;
690
691   for (extensions::ExtensionSet::const_iterator it = extensions->begin();
692        it != extensions->end(); ++it) {
693     const extensions::Extension* extension = it->get();
694     // Skip this extension if it's not an enterprise extension.
695     if (!extension->manifest()->HasPath(
696         extensions::manifest_keys::kStorageManagedSchema))
697       continue;
698     base::DictionaryValue* extension_policies = new base::DictionaryValue;
699     policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
700         policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
701     policy::PolicyErrorMap empty_error_map;
702     GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
703                     &empty_error_map, extension_policies);
704     extension_values->Set(extension->id(), extension_policies);
705   }
706   all_policies.Set("extensionPolicies", extension_values);
707 #endif
708   web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
709 }
710
711 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
712                                       policy::PolicyErrorMap* errors,
713                                       base::DictionaryValue* values) const {
714   for (policy::PolicyMap::const_iterator entry = map.begin();
715        entry != map.end(); ++entry) {
716     base::DictionaryValue* value = new base::DictionaryValue;
717     value->Set("value", CopyAndConvert(entry->second.value).release());
718     if (entry->second.scope == policy::POLICY_SCOPE_USER)
719       value->SetString("scope", "user");
720     else
721       value->SetString("scope", "machine");
722     if (entry->second.level == policy::POLICY_LEVEL_RECOMMENDED)
723       value->SetString("level", "recommended");
724     else
725       value->SetString("level", "mandatory");
726     base::string16 error = errors->GetErrors(entry->first);
727     if (!error.empty())
728       value->SetString("error", error);
729     values->Set(entry->first, value);
730   }
731 }
732
733 void PolicyUIHandler::GetChromePolicyValues(
734     base::DictionaryValue* values) const {
735   policy::PolicyService* policy_service = GetPolicyService();
736   policy::PolicyMap map;
737
738   // Make a copy that can be modified, since some policy values are modified
739   // before being displayed.
740   map.CopyFrom(policy_service->GetPolicies(
741       policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
742
743   // Get a list of all the errors in the policy values.
744   const policy::ConfigurationPolicyHandlerList* handler_list =
745       g_browser_process->browser_policy_connector()->GetHandlerList();
746   policy::PolicyErrorMap errors;
747   handler_list->ApplyPolicySettings(map, NULL, &errors);
748
749   // Convert dictionary values to strings for display.
750   handler_list->PrepareForDisplaying(&map);
751
752   GetPolicyValues(map, &errors, values);
753 }
754
755 void PolicyUIHandler::SendStatus() const {
756   scoped_ptr<base::DictionaryValue> device_status(new base::DictionaryValue);
757   device_status_provider_->GetStatus(device_status.get());
758   if (!device_domain_.empty())
759     device_status->SetString("domain", device_domain_);
760   scoped_ptr<base::DictionaryValue> user_status(new base::DictionaryValue);
761   user_status_provider_->GetStatus(user_status.get());
762   std::string username;
763   user_status->GetString("username", &username);
764   if (!username.empty())
765     user_status->SetString("domain", gaia::ExtractDomainName(username));
766
767   base::DictionaryValue status;
768   if (!device_status->empty())
769     status.Set("device", device_status.release());
770   if (!user_status->empty())
771     status.Set("user", user_status.release());
772
773   web_ui()->CallJavascriptFunction("policy.Page.setStatus", status);
774 }
775
776 void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
777   SendPolicyNames();
778   SendPolicyValues();
779   SendStatus();
780 }
781
782 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
783   GetPolicyService()->RefreshPolicies(
784       base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
785                  weak_factory_.GetWeakPtr()));
786 }
787
788 void PolicyUIHandler::OnRefreshPoliciesDone() const {
789   web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
790 }
791
792 policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
793   return policy::ProfilePolicyConnectorFactory::GetForProfile(
794       Profile::FromWebUI(web_ui()))->policy_service();
795 }
796
797 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) {
798   web_ui->AddMessageHandler(new PolicyUIHandler);
799   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
800                                 CreatePolicyUIHTMLSource());
801 }
802
803 PolicyUI::~PolicyUI() {
804 }