Home | History | Annotate | Download | only in webui
      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_manifest_constants.h"
     67 #include "chrome/common/extensions/extension_set.h"
     68 #include "chrome/common/extensions/manifest.h"
     69 #include "chrome/common/policy/policy_schema.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   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 
    335   content::NotificationRegistrar registrar_;
    336 
    337   DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
    338 };
    339 
    340 CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
    341 }
    342 
    343 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
    344 }
    345 
    346 void CloudPolicyStatusProvider::SetStatusChangeCallback(
    347     const base::Closure& callback) {
    348   callback_ = callback;
    349 }
    350 
    351 void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
    352 }
    353 
    354 void CloudPolicyStatusProvider::NotifyStatusChange() {
    355   if (!callback_.is_null())
    356     callback_.Run();
    357 }
    358 
    359 CloudPolicyCoreStatusProvider::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 
    367 CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
    368   core_->store()->RemoveObserver(this);
    369 }
    370 
    371 void CloudPolicyCoreStatusProvider::OnStoreLoaded(
    372     policy::CloudPolicyStore* store) {
    373   NotifyStatusChange();
    374 }
    375 
    376 void CloudPolicyCoreStatusProvider::OnStoreError(
    377     policy::CloudPolicyStore* store) {
    378   NotifyStatusChange();
    379 }
    380 
    381 UserPolicyStatusProvider::UserPolicyStatusProvider(
    382     policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
    383 }
    384 
    385 UserPolicyStatusProvider::~UserPolicyStatusProvider() {
    386 }
    387 
    388 void 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)
    396 DevicePolicyStatusProvider::DevicePolicyStatusProvider(
    397     policy::BrowserPolicyConnector* connector)
    398       : CloudPolicyCoreStatusProvider(
    399             connector->GetDeviceCloudPolicyManager()->core()) {
    400   domain_ = connector->GetEnterpriseDomain();
    401 }
    402 
    403 DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
    404 }
    405 
    406 void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
    407   GetStatusFromCore(core_, dict);
    408   dict->SetString("domain", domain_);
    409 }
    410 
    411 DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
    412     const std::string& user_id,
    413     policy::DeviceLocalAccountPolicyService* service)
    414       : user_id_(user_id),
    415         service_(service) {
    416   service_->AddObserver(this);
    417 }
    418 
    419 DeviceLocalAccountPolicyStatusProvider::
    420     ~DeviceLocalAccountPolicyStatusProvider() {
    421   service_->RemoveObserver(this);
    422 }
    423 
    424 void DeviceLocalAccountPolicyStatusProvider::GetStatus(
    425     base::DictionaryValue* dict) {
    426   const policy::DeviceLocalAccountPolicyBroker* broker =
    427       service_->GetBrokerForUser(user_id_);
    428   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));
    436     dict->SetString("username", std::string());
    437   }
    438   ExtractDomainFromUsername(dict);
    439   dict->SetBoolean("publicAccount", true);
    440 }
    441 
    442 void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
    443     const std::string& user_id) {
    444   if (user_id == user_id_)
    445     NotifyStatusChange();
    446 }
    447 
    448 void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
    449   NotifyStatusChange();
    450 }
    451 #endif
    452 
    453 PolicyUIHandler::PolicyUIHandler()
    454     : weak_factory_(this) {
    455 }
    456 
    457 PolicyUIHandler::~PolicyUIHandler() {
    458   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
    459   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
    460 }
    461 
    462 void PolicyUIHandler::RegisterMessages() {
    463 #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 {
    479     policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
    480         policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
    481             Profile::FromWebUI(web_ui()));
    482     if (user_cloud_policy_manager) {
    483       user_status_provider_.reset(
    484           new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
    485     }
    486   }
    487 #else
    488   policy::UserCloudPolicyManager* user_cloud_policy_manager =
    489       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);
    506   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
    507   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());
    515 
    516   web_ui()->RegisterMessageCallback(
    517       "initialized",
    518       base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this)));
    519   web_ui()->RegisterMessageCallback(
    520       "reloadPolicies",
    521       base::Bind(&PolicyUIHandler::HandleReloadPolicies,
    522                  base::Unretained(this)));
    523 }
    524 
    525 void 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 
    534 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
    535                                       const policy::PolicyMap& previous,
    536                                       const policy::PolicyMap& current) {
    537   SendPolicyValues();
    538 }
    539 
    540 void PolicyUIHandler::SendPolicyNames() const {
    541   base::DictionaryValue names;
    542 
    543   // Add Chrome policy names.
    544   base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
    545   const policy::PolicyDefinitionList* list =
    546       policy::GetChromePolicyDefinitionList();
    547   for (const policy::PolicyDefinitionList::Entry* entry = list->begin;
    548        entry != list->end; ++entry) {
    549     chrome_policy_names->SetBoolean(entry->name, true);
    550   }
    551   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 
    594   web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
    595 }
    596 
    597 void PolicyUIHandler::SendPolicyValues() const {
    598   base::DictionaryValue all_policies;
    599 
    600   // Add Chrome policy values.
    601   base::DictionaryValue* chrome_policies = new base::DictionaryValue;
    602   GetChromePolicyValues(chrome_policies);
    603   all_policies.Set("chromePolicies", chrome_policies);
    604 
    605 #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;
    612 
    613   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 
    633 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
    634                                       policy::PolicyErrorMap* errors,
    635                                       base::DictionaryValue* values) const {
    636   for (policy::PolicyMap::const_iterator entry = map.begin();
    637        entry != map.end(); ++entry) {
    638     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");
    648     string16 error = errors->GetErrors(entry->first);
    649     if (!error.empty())
    650       value->SetString("error", error);
    651     values->Set(entry->first, value);
    652   }
    653 }
    654 
    655 void 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);
    675 }
    676 
    677 void 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);
    696 }
    697 
    698 void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
    699   SendPolicyNames();
    700   SendPolicyValues();
    701   SendStatus();
    702 }
    703 
    704 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
    705   GetPolicyService()->RefreshPolicies(
    706       base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
    707                  weak_factory_.GetWeakPtr()));
    708 }
    709 
    710 void PolicyUIHandler::OnRefreshPoliciesDone() const {
    711   web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
    712 }
    713 
    714 policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
    715   return policy::ProfilePolicyConnectorFactory::GetForProfile(
    716       Profile::FromWebUI(web_ui()))->policy_service();
    717 }
    718 
    719 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) {
    720   web_ui->AddMessageHandler(new PolicyUIHandler);
    721   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
    722                                 CreatePolicyUIHTMLSource());
    723 }
    724 
    725 PolicyUI::~PolicyUI() {
    726 }
    727