policy_ui.cc revision bb1529ce867d8845a77ec7cdf3e3003ef1771a40
1561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes// Use of this source code is governed by a BSD-style license that can be
3561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes// found in the LICENSE file.
4561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
5561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/ui/webui/policy_ui.h"
6561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
7561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/bind.h"
8561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/bind_helpers.h"
9561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/callback.h"
10561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/compiler_specific.h"
11561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/logging.h"
12561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/memory/scoped_ptr.h"
13561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/memory/weak_ptr.h"
14561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/strings/string16.h"
15561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/time/time.h"
16561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "base/values.h"
17561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/browser_process.h"
18561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/chrome_notification_types.h"
198d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "chrome/browser/policy/browser_policy_connector.h"
208d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "chrome/browser/policy/cloud/cloud_policy_client.h"
21561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
22561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/cloud_policy_core.h"
23561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/cloud_policy_refresh_scheduler.h"
24561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/cloud_policy_store.h"
25561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/cloud_policy_validator.h"
26561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/message_util.h"
27561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/configuration_policy_handler_list.h"
28561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/policy_error_map.h"
29561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/policy_map.h"
30561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/policy_service.h"
31561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/policy_types.h"
32561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/profile_policy_connector.h"
33561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/profile_policy_connector_factory.h"
34561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
35561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/profiles/profile.h"
36561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/common/url_constants.h"
37561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "content/public/browser/notification_observer.h"
38561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "content/public/browser/notification_registrar.h"
398d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "content/public/browser/notification_service.h"
40561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "content/public/browser/web_ui.h"
41561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "content/public/browser/web_ui_data_source.h"
42561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "content/public/browser/web_ui_message_handler.h"
43561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "google_apis/gaia/gaia_auth_util.h"
44561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "grit/browser_resources.h"
45561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "grit/generated_resources.h"
46561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "policy/policy_constants.h"
47561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "ui/base/l10n/l10n_util.h"
48561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "ui/base/l10n/time_format.h"
49561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
50561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#if defined(OS_CHROMEOS)
518d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "chrome/browser/chromeos/login/user_manager.h"
52561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
53561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
54561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
558d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.h"
56561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#else
57561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
58561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
59561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#endif
608d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath
61561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#if !defined(OS_ANDROID) && !defined(OS_IOS)
62561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/extensions/extension_service.h"
63561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/browser/extensions/extension_system.h"
648d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "chrome/browser/policy/policy_domain_descriptor.h"
65561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/common/extensions/extension.h"
66561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/common/extensions/extension_manifest_constants.h"
67561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/common/extensions/extension_set.h"
688d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath#include "chrome/common/extensions/manifest.h"
69561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#include "chrome/common/policy/policy_schema.h"
70561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes#endif
71561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
728d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathnamespace em = enterprise_management;
73561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
74561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughesnamespace {
75561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
768d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamathcontent::WebUIDataSource* CreatePolicyUIHTMLSource() {
77561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  content::WebUIDataSource* source =
78561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes      content::WebUIDataSource::Create(chrome::kChromeUIPolicyHost);
79561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes
808d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath  // Localized strings.
81561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  source->AddLocalizedString("title", IDS_POLICY_TITLE);
82561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  source->AddLocalizedString("filterPlaceholder",
83561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes                             IDS_POLICY_FILTER_PLACEHOLDER);
848d8858e39800de641b50f6e8e864af9cf68bedeaNarayan Kamath  source->AddLocalizedString("reloadPolicies", IDS_POLICY_RELOAD_POLICIES);
85561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  source->AddLocalizedString("status", IDS_POLICY_STATUS);
86561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  source->AddLocalizedString("statusDevice", IDS_POLICY_STATUS_DEVICE);
87561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  source->AddLocalizedString("statusUser", IDS_POLICY_STATUS_USER);
88561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  source->AddLocalizedString("labelDomain", IDS_POLICY_LABEL_DOMAIN);
89561ee011997c6c2f1befbfaa9d5f0a99771c1d63Elliott Hughes  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
127void 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
163void 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.
173class 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.
196class 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.
216class 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.
230class 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.
251class 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.
276class 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
340CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
341}
342
343CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
344}
345
346void CloudPolicyStatusProvider::SetStatusChangeCallback(
347    const base::Closure& callback) {
348  callback_ = callback;
349}
350
351void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
352}
353
354void CloudPolicyStatusProvider::NotifyStatusChange() {
355  if (!callback_.is_null())
356    callback_.Run();
357}
358
359CloudPolicyCoreStatusProvider::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
367CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
368  core_->store()->RemoveObserver(this);
369}
370
371void CloudPolicyCoreStatusProvider::OnStoreLoaded(
372    policy::CloudPolicyStore* store) {
373  NotifyStatusChange();
374}
375
376void CloudPolicyCoreStatusProvider::OnStoreError(
377    policy::CloudPolicyStore* store) {
378  NotifyStatusChange();
379}
380
381UserPolicyStatusProvider::UserPolicyStatusProvider(
382    policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
383}
384
385UserPolicyStatusProvider::~UserPolicyStatusProvider() {
386}
387
388void 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)
396DevicePolicyStatusProvider::DevicePolicyStatusProvider(
397    policy::BrowserPolicyConnector* connector)
398      : CloudPolicyCoreStatusProvider(
399            connector->GetDeviceCloudPolicyManager()->core()) {
400  domain_ = connector->GetEnterpriseDomain();
401}
402
403DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
404}
405
406void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
407  GetStatusFromCore(core_, dict);
408  dict->SetString("domain", domain_);
409}
410
411DeviceLocalAccountPolicyStatusProvider::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
419DeviceLocalAccountPolicyStatusProvider::
420    ~DeviceLocalAccountPolicyStatusProvider() {
421  service_->RemoveObserver(this);
422}
423
424void 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
442void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
443    const std::string& user_id) {
444  if (user_id == user_id_)
445    NotifyStatusChange();
446}
447
448void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
449  NotifyStatusChange();
450}
451#endif
452
453PolicyUIHandler::PolicyUIHandler()
454    : weak_factory_(this) {
455}
456
457PolicyUIHandler::~PolicyUIHandler() {
458  GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
459  GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
460}
461
462void 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
525void 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
534void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
535                                      const policy::PolicyMap& previous,
536                                      const policy::PolicyMap& current) {
537  SendPolicyValues();
538}
539
540void 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
597void 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
633void 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
655void 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
677void 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
698void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
699  SendPolicyNames();
700  SendPolicyValues();
701  SendStatus();
702}
703
704void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
705  GetPolicyService()->RefreshPolicies(
706      base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
707                 weak_factory_.GetWeakPtr()));
708}
709
710void PolicyUIHandler::OnRefreshPoliciesDone() const {
711  web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
712}
713
714policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
715  return policy::ProfilePolicyConnectorFactory::GetForProfile(
716      Profile::FromWebUI(web_ui()))->policy_service();
717}
718
719PolicyUI::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
725PolicyUI::~PolicyUI() {
726}
727