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