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/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->SetUseJsonJSFormatV2();
    123   source->SetJsonPath("strings.js");
    124 
    125   // Add required resources.
    126   source->AddResourcePath("policy.css", IDR_POLICY_CSS);
    127   source->AddResourcePath("policy.js", IDR_POLICY_JS);
    128   source->AddResourcePath("uber_utils.js", IDR_UBER_UTILS_JS);
    129   source->SetDefaultResource(IDR_POLICY_HTML);
    130 
    131   return source;
    132 }
    133 
    134 // Formats the association state indicated by |data|. If |data| is NULL, the
    135 // state is considered to be UNMANAGED.
    136 base::string16 FormatAssociationState(const em::PolicyData* data) {
    137   if (data) {
    138     switch (data->state()) {
    139       case em::PolicyData::ACTIVE:
    140         return l10n_util::GetStringUTF16(IDS_POLICY_ASSOCIATION_STATE_ACTIVE);
    141       case em::PolicyData::UNMANAGED:
    142         return l10n_util::GetStringUTF16(
    143             IDS_POLICY_ASSOCIATION_STATE_UNMANAGED);
    144       case em::PolicyData::DEPROVISIONED:
    145         return l10n_util::GetStringUTF16(
    146             IDS_POLICY_ASSOCIATION_STATE_DEPROVISIONED);
    147     }
    148     NOTREACHED() << "Unknown state " << data->state();
    149   }
    150 
    151   // Default to UNMANAGED for the case of missing policy or bad state enum.
    152   return l10n_util::GetStringUTF16(IDS_POLICY_ASSOCIATION_STATE_UNMANAGED);
    153 }
    154 
    155 void GetStatusFromCore(const policy::CloudPolicyCore* core,
    156                        base::DictionaryValue* dict) {
    157   const policy::CloudPolicyStore* store = core->store();
    158   const policy::CloudPolicyClient* client = core->client();
    159   const policy::CloudPolicyRefreshScheduler* refresh_scheduler =
    160         core->refresh_scheduler();
    161 
    162   // CloudPolicyStore errors take precedence to show in the status message.
    163   // Other errors (such as transient policy fetching problems) get displayed
    164   // only if CloudPolicyStore is in STATUS_OK.
    165   base::string16 status =
    166       policy::FormatStoreStatus(store->status(), store->validation_status());
    167   if (store->status() == policy::CloudPolicyStore::STATUS_OK) {
    168     if (client && client->status() != policy::DM_STATUS_SUCCESS)
    169       status = policy::FormatDeviceManagementStatus(client->status());
    170     else if (!store->is_managed())
    171       status = FormatAssociationState(store->policy());
    172   }
    173 
    174   const em::PolicyData* policy = store->policy();
    175   std::string client_id = policy ? policy->device_id() : std::string();
    176   std::string username = policy ? policy->username() : std::string();
    177   base::TimeDelta refresh_interval =
    178       base::TimeDelta::FromMilliseconds(refresh_scheduler ?
    179           refresh_scheduler->refresh_delay() :
    180           policy::CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
    181   base::Time last_refresh_time = refresh_scheduler ?
    182       refresh_scheduler->last_refresh() : base::Time();
    183 
    184   bool no_error = store->status() == policy::CloudPolicyStore::STATUS_OK &&
    185                   client && client->status() == policy::DM_STATUS_SUCCESS;
    186   dict->SetBoolean("error", !no_error);
    187   dict->SetString("status", status);
    188   dict->SetString("clientId", client_id);
    189   dict->SetString("username", username);
    190   dict->SetString("refreshInterval",
    191                   ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
    192                                          ui::TimeFormat::LENGTH_SHORT,
    193                                          refresh_interval));
    194   dict->SetString("timeSinceLastRefresh", last_refresh_time.is_null() ?
    195       l10n_util::GetStringUTF16(IDS_POLICY_NEVER_FETCHED) :
    196       ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
    197                              ui::TimeFormat::LENGTH_SHORT,
    198                              base::Time::NowFromSystemTime() -
    199                                  last_refresh_time));
    200 }
    201 
    202 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
    203   std::string username;
    204   dict->GetString("username", &username);
    205   if (!username.empty())
    206     dict->SetString("domain", gaia::ExtractDomainName(username));
    207 }
    208 
    209 // Utility function that returns a JSON serialization of the given |dict|.
    210 scoped_ptr<base::StringValue> DictionaryToJSONString(
    211     const base::DictionaryValue* dict) {
    212   std::string json_string;
    213   base::JSONWriter::WriteWithOptions(dict,
    214                                      base::JSONWriter::OPTIONS_PRETTY_PRINT,
    215                                      &json_string);
    216   return make_scoped_ptr(new base::StringValue(json_string));
    217 }
    218 
    219 // Returns a copy of |value| with some values converted to a representation that
    220 // i18n_template.js will display in a nicer way.
    221 scoped_ptr<base::Value> CopyAndConvert(const base::Value* value) {
    222   const base::DictionaryValue* dict = NULL;
    223   if (value->GetAsDictionary(&dict))
    224     return DictionaryToJSONString(dict).PassAs<base::Value>();
    225 
    226   scoped_ptr<base::Value> copy(value->DeepCopy());
    227   base::ListValue* list = NULL;
    228   if (copy->GetAsList(&list)) {
    229     for (size_t i = 0; i < list->GetSize(); ++i) {
    230       if (list->GetDictionary(i, &dict))
    231         list->Set(i, DictionaryToJSONString(dict).release());
    232     }
    233   }
    234 
    235   return copy.Pass();
    236 }
    237 
    238 }  // namespace
    239 
    240 // An interface for querying the status of cloud policy.
    241 class CloudPolicyStatusProvider {
    242  public:
    243   CloudPolicyStatusProvider();
    244   virtual ~CloudPolicyStatusProvider();
    245 
    246   // Sets a callback to invoke upon status changes.
    247   void SetStatusChangeCallback(const base::Closure& callback);
    248 
    249   virtual void GetStatus(base::DictionaryValue* dict);
    250 
    251  protected:
    252   void NotifyStatusChange();
    253 
    254  private:
    255   base::Closure callback_;
    256 
    257   DISALLOW_COPY_AND_ASSIGN(CloudPolicyStatusProvider);
    258 };
    259 
    260 // Status provider implementation that pulls cloud policy status from a
    261 // CloudPolicyCore instance provided at construction time. Also listens for
    262 // changes on that CloudPolicyCore and reports them through the status change
    263 // callback.
    264 class CloudPolicyCoreStatusProvider
    265     : public CloudPolicyStatusProvider,
    266       public policy::CloudPolicyStore::Observer {
    267  public:
    268   explicit CloudPolicyCoreStatusProvider(policy::CloudPolicyCore* core);
    269   virtual ~CloudPolicyCoreStatusProvider();
    270 
    271   // policy::CloudPolicyStore::Observer implementation.
    272   virtual void OnStoreLoaded(policy::CloudPolicyStore* store) OVERRIDE;
    273   virtual void OnStoreError(policy::CloudPolicyStore* store) OVERRIDE;
    274 
    275  protected:
    276   // Policy status is read from the CloudPolicyClient, CloudPolicyStore and
    277   // CloudPolicyRefreshScheduler hosted by this |core_|.
    278   policy::CloudPolicyCore* core_;
    279 
    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   virtual ~UserPolicyStatusProvider();
    288 
    289   // CloudPolicyCoreStatusProvider implementation.
    290   virtual 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   virtual ~PolicyUIHandler();
    350 
    351   // content::NotificationObserver implementation.
    352   virtual void Observe(int type,
    353                        const content::NotificationSource& source,
    354                        const content::NotificationDetails& details) OVERRIDE;
    355 
    356   // content::WebUIMessageHandler implementation.
    357   virtual void RegisterMessages() OVERRIDE;
    358 
    359   // policy::PolicyService::Observer implementation.
    360   virtual 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   content::NotificationRegistrar registrar_;
    403 
    404   base::WeakPtrFactory<PolicyUIHandler> weak_factory_;
    405 
    406   DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
    407 };
    408 
    409 CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
    410 }
    411 
    412 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
    413 }
    414 
    415 void CloudPolicyStatusProvider::SetStatusChangeCallback(
    416     const base::Closure& callback) {
    417   callback_ = callback;
    418 }
    419 
    420 void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
    421 }
    422 
    423 void CloudPolicyStatusProvider::NotifyStatusChange() {
    424   if (!callback_.is_null())
    425     callback_.Run();
    426 }
    427 
    428 CloudPolicyCoreStatusProvider::CloudPolicyCoreStatusProvider(
    429     policy::CloudPolicyCore* core) : core_(core) {
    430   core_->store()->AddObserver(this);
    431   // TODO(bartfab): Add an observer that watches for client errors. Observing
    432   // core_->client() directly is not safe as the client may be destroyed and
    433   // (re-)created anytime if the user signs in or out on desktop platforms.
    434 }
    435 
    436 CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
    437   core_->store()->RemoveObserver(this);
    438 }
    439 
    440 void CloudPolicyCoreStatusProvider::OnStoreLoaded(
    441     policy::CloudPolicyStore* store) {
    442   NotifyStatusChange();
    443 }
    444 
    445 void CloudPolicyCoreStatusProvider::OnStoreError(
    446     policy::CloudPolicyStore* store) {
    447   NotifyStatusChange();
    448 }
    449 
    450 UserPolicyStatusProvider::UserPolicyStatusProvider(
    451     policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
    452 }
    453 
    454 UserPolicyStatusProvider::~UserPolicyStatusProvider() {
    455 }
    456 
    457 void UserPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
    458   if (!core_->store()->is_managed())
    459     return;
    460   GetStatusFromCore(core_, dict);
    461   ExtractDomainFromUsername(dict);
    462 }
    463 
    464 #if defined(OS_CHROMEOS)
    465 DevicePolicyStatusProvider::DevicePolicyStatusProvider(
    466     policy::BrowserPolicyConnectorChromeOS* connector)
    467       : CloudPolicyCoreStatusProvider(
    468             connector->GetDeviceCloudPolicyManager()->core()) {
    469   domain_ = connector->GetEnterpriseDomain();
    470 }
    471 
    472 DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
    473 }
    474 
    475 void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
    476   GetStatusFromCore(core_, dict);
    477   dict->SetString("domain", domain_);
    478 }
    479 
    480 DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
    481     const std::string& user_id,
    482     policy::DeviceLocalAccountPolicyService* service)
    483       : user_id_(user_id),
    484         service_(service) {
    485   service_->AddObserver(this);
    486 }
    487 
    488 DeviceLocalAccountPolicyStatusProvider::
    489     ~DeviceLocalAccountPolicyStatusProvider() {
    490   service_->RemoveObserver(this);
    491 }
    492 
    493 void DeviceLocalAccountPolicyStatusProvider::GetStatus(
    494     base::DictionaryValue* dict) {
    495   const policy::DeviceLocalAccountPolicyBroker* broker =
    496       service_->GetBrokerForUser(user_id_);
    497   if (broker) {
    498     GetStatusFromCore(broker->core(), dict);
    499   } else {
    500     dict->SetBoolean("error", true);
    501     dict->SetString("status",
    502                     policy::FormatStoreStatus(
    503                         policy::CloudPolicyStore::STATUS_BAD_STATE,
    504                         policy::CloudPolicyValidatorBase::VALIDATION_OK));
    505     dict->SetString("username", std::string());
    506   }
    507   ExtractDomainFromUsername(dict);
    508   dict->SetBoolean("publicAccount", true);
    509 }
    510 
    511 void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
    512     const std::string& user_id) {
    513   if (user_id == user_id_)
    514     NotifyStatusChange();
    515 }
    516 
    517 void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
    518   NotifyStatusChange();
    519 }
    520 #endif
    521 
    522 PolicyUIHandler::PolicyUIHandler()
    523     : initialized_(false),
    524       weak_factory_(this) {
    525 }
    526 
    527 PolicyUIHandler::~PolicyUIHandler() {
    528   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
    529   GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
    530 }
    531 
    532 void PolicyUIHandler::RegisterMessages() {
    533 #if defined(OS_CHROMEOS)
    534   policy::BrowserPolicyConnectorChromeOS* connector =
    535       g_browser_process->platform_part()->browser_policy_connector_chromeos();
    536   if (connector->IsEnterpriseManaged())
    537     device_status_provider_.reset(new DevicePolicyStatusProvider(connector));
    538 
    539   const user_manager::UserManager* user_manager =
    540       user_manager::UserManager::Get();
    541   if (user_manager->IsLoggedInAsPublicAccount()) {
    542     policy::DeviceLocalAccountPolicyService* local_account_service =
    543         connector->GetDeviceLocalAccountPolicyService();
    544     if (local_account_service) {
    545       user_status_provider_.reset(
    546           new DeviceLocalAccountPolicyStatusProvider(
    547               user_manager->GetLoggedInUser()->email(), local_account_service));
    548     }
    549   } else {
    550     policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
    551         policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
    552             Profile::FromWebUI(web_ui()));
    553     if (user_cloud_policy_manager) {
    554       user_status_provider_.reset(
    555           new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
    556     }
    557   }
    558 #else
    559   policy::UserCloudPolicyManager* user_cloud_policy_manager =
    560       policy::UserCloudPolicyManagerFactory::GetForBrowserContext(
    561           web_ui()->GetWebContents()->GetBrowserContext());
    562   if (user_cloud_policy_manager) {
    563     user_status_provider_.reset(
    564         new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
    565   }
    566 #endif
    567 
    568   if (!user_status_provider_.get())
    569     user_status_provider_.reset(new CloudPolicyStatusProvider());
    570   if (!device_status_provider_.get())
    571     device_status_provider_.reset(new CloudPolicyStatusProvider());
    572 
    573   base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus,
    574                                            base::Unretained(this)));
    575   user_status_provider_->SetStatusChangeCallback(update_callback);
    576   device_status_provider_->SetStatusChangeCallback(update_callback);
    577   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
    578   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
    579 
    580   registrar_.Add(this,
    581                  extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    582                  content::NotificationService::AllSources());
    583   registrar_.Add(this,
    584                  extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
    585                  content::NotificationService::AllSources());
    586 
    587   web_ui()->RegisterMessageCallback(
    588       "initialized",
    589       base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this)));
    590   web_ui()->RegisterMessageCallback(
    591       "reloadPolicies",
    592       base::Bind(&PolicyUIHandler::HandleReloadPolicies,
    593                  base::Unretained(this)));
    594 }
    595 
    596 void PolicyUIHandler::Observe(int type,
    597                               const content::NotificationSource& source,
    598                               const content::NotificationDetails& details) {
    599   DCHECK(type == extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED ||
    600          type == extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED);
    601   SendPolicyNames();
    602   SendPolicyValues();
    603 }
    604 
    605 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
    606                                       const policy::PolicyMap& previous,
    607                                       const policy::PolicyMap& current) {
    608   SendPolicyValues();
    609 }
    610 
    611 void PolicyUIHandler::SendPolicyNames() const {
    612   base::DictionaryValue names;
    613 
    614   Profile* profile = Profile::FromWebUI(web_ui());
    615   policy::SchemaRegistry* registry =
    616       policy::SchemaRegistryServiceFactory::GetForContext(
    617           profile->GetOriginalProfile())->registry();
    618   scoped_refptr<policy::SchemaMap> schema_map = registry->schema_map();
    619 
    620   // Add Chrome policy names.
    621   base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
    622   policy::PolicyNamespace chrome_ns(policy::POLICY_DOMAIN_CHROME, "");
    623   const policy::Schema* chrome_schema = schema_map->GetSchema(chrome_ns);
    624   for (policy::Schema::Iterator it = chrome_schema->GetPropertiesIterator();
    625        !it.IsAtEnd(); it.Advance()) {
    626     chrome_policy_names->SetBoolean(it.key(), true);
    627   }
    628   names.Set("chromePolicyNames", chrome_policy_names);
    629 
    630 #if !defined(OS_ANDROID) && !defined(OS_IOS)
    631   // Add extension policy names.
    632   base::DictionaryValue* extension_policy_names = new base::DictionaryValue;
    633 
    634   extensions::ExtensionSystem* extension_system =
    635       extensions::ExtensionSystem::Get(profile);
    636   const extensions::ExtensionSet* extensions =
    637       extension_system->extension_service()->extensions();
    638 
    639   for (extensions::ExtensionSet::const_iterator it = extensions->begin();
    640        it != extensions->end(); ++it) {
    641     const extensions::Extension* extension = it->get();
    642     // Skip this extension if it's not an enterprise extension.
    643     if (!extension->manifest()->HasPath(
    644         extensions::manifest_keys::kStorageManagedSchema))
    645       continue;
    646     base::DictionaryValue* extension_value = new base::DictionaryValue;
    647     extension_value->SetString("name", extension->name());
    648     const policy::Schema* schema =
    649         schema_map->GetSchema(policy::PolicyNamespace(
    650             policy::POLICY_DOMAIN_EXTENSIONS, extension->id()));
    651     base::DictionaryValue* policy_names = new base::DictionaryValue;
    652     if (schema && schema->valid()) {
    653       // Get policy names from the extension's policy schema.
    654       // Store in a map, not an array, for faster lookup on JS side.
    655       for (policy::Schema::Iterator prop = schema->GetPropertiesIterator();
    656            !prop.IsAtEnd(); prop.Advance()) {
    657         policy_names->SetBoolean(prop.key(), true);
    658       }
    659     }
    660     extension_value->Set("policyNames", policy_names);
    661     extension_policy_names->Set(extension->id(), extension_value);
    662   }
    663   names.Set("extensionPolicyNames", extension_policy_names);
    664 #endif
    665 
    666   web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
    667 }
    668 
    669 void PolicyUIHandler::SendPolicyValues() const {
    670   base::DictionaryValue all_policies;
    671 
    672   // Add Chrome policy values.
    673   base::DictionaryValue* chrome_policies = new base::DictionaryValue;
    674   GetChromePolicyValues(chrome_policies);
    675   all_policies.Set("chromePolicies", chrome_policies);
    676 
    677 #if !defined(OS_ANDROID) && !defined(OS_IOS)
    678   // Add extension policy values.
    679   extensions::ExtensionSystem* extension_system =
    680       extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
    681   const extensions::ExtensionSet* extensions =
    682       extension_system->extension_service()->extensions();
    683   base::DictionaryValue* extension_values = new base::DictionaryValue;
    684 
    685   for (extensions::ExtensionSet::const_iterator it = extensions->begin();
    686        it != extensions->end(); ++it) {
    687     const extensions::Extension* extension = it->get();
    688     // Skip this extension if it's not an enterprise extension.
    689     if (!extension->manifest()->HasPath(
    690         extensions::manifest_keys::kStorageManagedSchema))
    691       continue;
    692     base::DictionaryValue* extension_policies = new base::DictionaryValue;
    693     policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
    694         policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
    695     policy::PolicyErrorMap empty_error_map;
    696     GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
    697                     &empty_error_map, extension_policies);
    698     extension_values->Set(extension->id(), extension_policies);
    699   }
    700   all_policies.Set("extensionPolicies", extension_values);
    701 #endif
    702   web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
    703 }
    704 
    705 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
    706                                       policy::PolicyErrorMap* errors,
    707                                       base::DictionaryValue* values) const {
    708   for (policy::PolicyMap::const_iterator entry = map.begin();
    709        entry != map.end(); ++entry) {
    710     base::DictionaryValue* value = new base::DictionaryValue;
    711     value->Set("value", CopyAndConvert(entry->second.value).release());
    712     if (entry->second.scope == policy::POLICY_SCOPE_USER)
    713       value->SetString("scope", "user");
    714     else
    715       value->SetString("scope", "machine");
    716     if (entry->second.level == policy::POLICY_LEVEL_RECOMMENDED)
    717       value->SetString("level", "recommended");
    718     else
    719       value->SetString("level", "mandatory");
    720     base::string16 error = errors->GetErrors(entry->first);
    721     if (!error.empty())
    722       value->SetString("error", error);
    723     values->Set(entry->first, value);
    724   }
    725 }
    726 
    727 void PolicyUIHandler::GetChromePolicyValues(
    728     base::DictionaryValue* values) const {
    729   policy::PolicyService* policy_service = GetPolicyService();
    730   policy::PolicyMap map;
    731 
    732   // Make a copy that can be modified, since some policy values are modified
    733   // before being displayed.
    734   map.CopyFrom(policy_service->GetPolicies(
    735       policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
    736 
    737   // Get a list of all the errors in the policy values.
    738   const policy::ConfigurationPolicyHandlerList* handler_list =
    739       g_browser_process->browser_policy_connector()->GetHandlerList();
    740   policy::PolicyErrorMap errors;
    741   handler_list->ApplyPolicySettings(map, NULL, &errors);
    742 
    743   // Convert dictionary values to strings for display.
    744   handler_list->PrepareForDisplaying(&map);
    745 
    746   GetPolicyValues(map, &errors, values);
    747 }
    748 
    749 void PolicyUIHandler::SendStatus() const {
    750   scoped_ptr<base::DictionaryValue> device_status(new base::DictionaryValue);
    751   device_status_provider_->GetStatus(device_status.get());
    752   if (!device_domain_.empty())
    753     device_status->SetString("domain", device_domain_);
    754   scoped_ptr<base::DictionaryValue> user_status(new base::DictionaryValue);
    755   user_status_provider_->GetStatus(user_status.get());
    756   std::string username;
    757   user_status->GetString("username", &username);
    758   if (!username.empty())
    759     user_status->SetString("domain", gaia::ExtractDomainName(username));
    760 
    761   base::DictionaryValue status;
    762   if (!device_status->empty())
    763     status.Set("device", device_status.release());
    764   if (!user_status->empty())
    765     status.Set("user", user_status.release());
    766 
    767   web_ui()->CallJavascriptFunction("policy.Page.setStatus", status);
    768 }
    769 
    770 void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
    771   SendPolicyNames();
    772   SendPolicyValues();
    773   SendStatus();
    774 }
    775 
    776 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
    777   GetPolicyService()->RefreshPolicies(
    778       base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
    779                  weak_factory_.GetWeakPtr()));
    780 }
    781 
    782 void PolicyUIHandler::OnRefreshPoliciesDone() const {
    783   web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
    784 }
    785 
    786 policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
    787   return policy::ProfilePolicyConnectorFactory::GetForProfile(
    788       Profile::FromWebUI(web_ui()))->policy_service();
    789 }
    790 
    791 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) {
    792   web_ui->AddMessageHandler(new PolicyUIHandler);
    793   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
    794                                 CreatePolicyUIHTMLSource());
    795 }
    796 
    797 PolicyUI::~PolicyUI() {
    798 }
    799