Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / webui / policy_ui.cc
blob2d121f6a099d254fc706b32197e00d4a47b167c7
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.
5 #include "chrome/browser/ui/webui/policy_ui.h"
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"
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
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 "extensions/common/extension.h"
73 #include "extensions/common/extension_set.h"
74 #include "extensions/common/manifest.h"
75 #include "extensions/common/manifest_constants.h"
76 #endif
78 namespace em = enterprise_management;
80 namespace {
82 content::WebUIDataSource* CreatePolicyUIHTMLSource() {
83 content::WebUIDataSource* source =
84 content::WebUIDataSource::Create(chrome::kChromeUIPolicyHost);
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);
121 source->SetUseJsonJSFormatV2();
122 source->SetJsonPath("strings.js");
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);
130 return source;
133 // Formats the association state indicated by |data|. If |data| is NULL, the
134 // state is considered to be UNMANAGED.
135 base::string16 FormatAssociationState(const em::PolicyData* data) {
136 if (data) {
137 switch (data->state()) {
138 case em::PolicyData::ACTIVE:
139 return l10n_util::GetStringUTF16(IDS_POLICY_ASSOCIATION_STATE_ACTIVE);
140 case em::PolicyData::UNMANAGED:
141 return l10n_util::GetStringUTF16(
142 IDS_POLICY_ASSOCIATION_STATE_UNMANAGED);
143 case em::PolicyData::DEPROVISIONED:
144 return l10n_util::GetStringUTF16(
145 IDS_POLICY_ASSOCIATION_STATE_DEPROVISIONED);
147 NOTREACHED() << "Unknown state " << data->state();
150 // Default to UNMANAGED for the case of missing policy or bad state enum.
151 return l10n_util::GetStringUTF16(IDS_POLICY_ASSOCIATION_STATE_UNMANAGED);
154 void GetStatusFromCore(const policy::CloudPolicyCore* core,
155 base::DictionaryValue* dict) {
156 const policy::CloudPolicyStore* store = core->store();
157 const policy::CloudPolicyClient* client = core->client();
158 const policy::CloudPolicyRefreshScheduler* refresh_scheduler =
159 core->refresh_scheduler();
161 // CloudPolicyStore errors take precedence to show in the status message.
162 // Other errors (such as transient policy fetching problems) get displayed
163 // only if CloudPolicyStore is in STATUS_OK.
164 base::string16 status =
165 policy::FormatStoreStatus(store->status(), store->validation_status());
166 if (store->status() == policy::CloudPolicyStore::STATUS_OK) {
167 if (client && client->status() != policy::DM_STATUS_SUCCESS)
168 status = policy::FormatDeviceManagementStatus(client->status());
169 else if (!store->is_managed())
170 status = FormatAssociationState(store->policy());
173 const em::PolicyData* policy = store->policy();
174 std::string client_id = policy ? policy->device_id() : std::string();
175 std::string username = policy ? policy->username() : std::string();
176 base::TimeDelta refresh_interval =
177 base::TimeDelta::FromMilliseconds(refresh_scheduler ?
178 refresh_scheduler->refresh_delay() :
179 policy::CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs);
180 base::Time last_refresh_time = refresh_scheduler ?
181 refresh_scheduler->last_refresh() : base::Time();
183 bool no_error = store->status() == policy::CloudPolicyStore::STATUS_OK &&
184 client && client->status() == policy::DM_STATUS_SUCCESS;
185 dict->SetBoolean("error", !no_error);
186 dict->SetString("status", status);
187 dict->SetString("clientId", client_id);
188 dict->SetString("username", username);
189 dict->SetString("refreshInterval",
190 ui::TimeFormat::TimeRemainingShort(refresh_interval));
191 dict->SetString("timeSinceLastRefresh", last_refresh_time.is_null() ?
192 l10n_util::GetStringUTF16(IDS_POLICY_NEVER_FETCHED) :
193 ui::TimeFormat::TimeElapsed(base::Time::NowFromSystemTime() -
194 last_refresh_time));
197 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
198 std::string username;
199 dict->GetString("username", &username);
200 if (!username.empty())
201 dict->SetString("domain", gaia::ExtractDomainName(username));
204 // Utility function that returns a JSON serialization of the given |dict|.
205 scoped_ptr<base::StringValue> DictionaryToJSONString(
206 const base::DictionaryValue* dict) {
207 std::string json_string;
208 base::JSONWriter::WriteWithOptions(dict,
209 base::JSONWriter::OPTIONS_PRETTY_PRINT,
210 &json_string);
211 return make_scoped_ptr(new base::StringValue(json_string));
214 // Returns a copy of |value| with some values converted to a representation that
215 // i18n_template.js will display in a nicer way.
216 scoped_ptr<base::Value> CopyAndConvert(const base::Value* value) {
217 const base::DictionaryValue* dict = NULL;
218 if (value->GetAsDictionary(&dict))
219 return DictionaryToJSONString(dict).PassAs<base::Value>();
221 scoped_ptr<base::Value> copy(value->DeepCopy());
222 base::ListValue* list = NULL;
223 if (copy->GetAsList(&list)) {
224 for (size_t i = 0; i < list->GetSize(); ++i) {
225 if (list->GetDictionary(i, &dict))
226 list->Set(i, DictionaryToJSONString(dict).release());
230 return copy.Pass();
233 } // namespace
235 // An interface for querying the status of cloud policy.
236 class CloudPolicyStatusProvider {
237 public:
238 CloudPolicyStatusProvider();
239 virtual ~CloudPolicyStatusProvider();
241 // Sets a callback to invoke upon status changes.
242 void SetStatusChangeCallback(const base::Closure& callback);
244 virtual void GetStatus(base::DictionaryValue* dict);
246 protected:
247 void NotifyStatusChange();
249 private:
250 base::Closure callback_;
252 DISALLOW_COPY_AND_ASSIGN(CloudPolicyStatusProvider);
255 // Status provider implementation that pulls cloud policy status from a
256 // CloudPolicyCore instance provided at construction time. Also listens for
257 // changes on that CloudPolicyCore and reports them through the status change
258 // callback.
259 class CloudPolicyCoreStatusProvider
260 : public CloudPolicyStatusProvider,
261 public policy::CloudPolicyStore::Observer {
262 public:
263 explicit CloudPolicyCoreStatusProvider(policy::CloudPolicyCore* core);
264 virtual ~CloudPolicyCoreStatusProvider();
266 // policy::CloudPolicyStore::Observer implementation.
267 virtual void OnStoreLoaded(policy::CloudPolicyStore* store) OVERRIDE;
268 virtual void OnStoreError(policy::CloudPolicyStore* store) OVERRIDE;
270 protected:
271 // Policy status is read from the CloudPolicyClient, CloudPolicyStore and
272 // CloudPolicyRefreshScheduler hosted by this |core_|.
273 policy::CloudPolicyCore* core_;
275 DISALLOW_COPY_AND_ASSIGN(CloudPolicyCoreStatusProvider);
278 // A cloud policy status provider for user policy.
279 class UserPolicyStatusProvider : public CloudPolicyCoreStatusProvider {
280 public:
281 explicit UserPolicyStatusProvider(policy::CloudPolicyCore* core);
282 virtual ~UserPolicyStatusProvider();
284 // CloudPolicyCoreStatusProvider implementation.
285 virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
287 private:
288 DISALLOW_COPY_AND_ASSIGN(UserPolicyStatusProvider);
291 #if defined(OS_CHROMEOS)
292 // A cloud policy status provider for device policy.
293 class DevicePolicyStatusProvider : public CloudPolicyCoreStatusProvider {
294 public:
295 explicit DevicePolicyStatusProvider(
296 policy::BrowserPolicyConnector* connector);
297 virtual ~DevicePolicyStatusProvider();
299 // CloudPolicyCoreStatusProvider implementation.
300 virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
302 private:
303 std::string domain_;
305 DISALLOW_COPY_AND_ASSIGN(DevicePolicyStatusProvider);
308 // A cloud policy status provider that reads policy status from the policy core
309 // associated with the device-local account specified by |user_id| at
310 // construction time. The indirection via user ID and
311 // DeviceLocalAccountPolicyService is necessary because the device-local account
312 // may go away any time behind the scenes, at which point the status message
313 // text will indicate CloudPolicyStore::STATUS_BAD_STATE.
314 class DeviceLocalAccountPolicyStatusProvider
315 : public CloudPolicyStatusProvider,
316 public policy::DeviceLocalAccountPolicyService::Observer {
317 public:
318 DeviceLocalAccountPolicyStatusProvider(
319 const std::string& user_id,
320 policy::DeviceLocalAccountPolicyService* service);
321 virtual ~DeviceLocalAccountPolicyStatusProvider();
323 // CloudPolicyStatusProvider implementation.
324 virtual void GetStatus(base::DictionaryValue* dict) OVERRIDE;
326 // policy::DeviceLocalAccountPolicyService::Observer implementation.
327 virtual void OnPolicyUpdated(const std::string& user_id) OVERRIDE;
328 virtual void OnDeviceLocalAccountsChanged() OVERRIDE;
330 private:
331 const std::string user_id_;
332 policy::DeviceLocalAccountPolicyService* service_;
334 DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyStatusProvider);
336 #endif
338 // The JavaScript message handler for the chrome://policy page.
339 class PolicyUIHandler : public content::NotificationObserver,
340 public content::WebUIMessageHandler,
341 public policy::PolicyService::Observer {
342 public:
343 PolicyUIHandler();
344 virtual ~PolicyUIHandler();
346 // content::NotificationObserver implementation.
347 virtual void Observe(int type,
348 const content::NotificationSource& source,
349 const content::NotificationDetails& details) OVERRIDE;
351 // content::WebUIMessageHandler implementation.
352 virtual void RegisterMessages() OVERRIDE;
354 // policy::PolicyService::Observer implementation.
355 virtual void OnPolicyUpdated(const policy::PolicyNamespace& ns,
356 const policy::PolicyMap& previous,
357 const policy::PolicyMap& current) OVERRIDE;
359 private:
360 // Send a dictionary containing the names of all known policies to the UI.
361 void SendPolicyNames() const;
363 // Send information about the current policy values to the UI. For each policy
364 // whose value has been set, a dictionary containing the value and additional
365 // metadata is sent.
366 void SendPolicyValues() const;
368 // Send the status of cloud policy to the UI. For each scope that has cloud
369 // policy enabled (device and/or user), a dictionary containing status
370 // information is sent.
371 void SendStatus() const;
373 // Inserts a description of each policy in |policy_map| into |values|, using
374 // the optional errors in |errors| to determine the status of each policy.
375 void GetPolicyValues(const policy::PolicyMap& policy_map,
376 policy::PolicyErrorMap* errors,
377 base::DictionaryValue* values) const;
379 void GetChromePolicyValues(base::DictionaryValue* values) const;
381 void HandleInitialized(const base::ListValue* args);
382 void HandleReloadPolicies(const base::ListValue* args);
384 void OnRefreshPoliciesDone() const;
386 policy::PolicyService* GetPolicyService() const;
388 bool initialized_;
389 std::string device_domain_;
391 // Providers that supply status dictionaries for user and device policy,
392 // respectively. These are created on initialization time as appropriate for
393 // the platform (Chrome OS / desktop) and type of policy that is in effect.
394 scoped_ptr<CloudPolicyStatusProvider> user_status_provider_;
395 scoped_ptr<CloudPolicyStatusProvider> device_status_provider_;
397 content::NotificationRegistrar registrar_;
399 base::WeakPtrFactory<PolicyUIHandler> weak_factory_;
401 DISALLOW_COPY_AND_ASSIGN(PolicyUIHandler);
404 CloudPolicyStatusProvider::CloudPolicyStatusProvider() {
407 CloudPolicyStatusProvider::~CloudPolicyStatusProvider() {
410 void CloudPolicyStatusProvider::SetStatusChangeCallback(
411 const base::Closure& callback) {
412 callback_ = callback;
415 void CloudPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
418 void CloudPolicyStatusProvider::NotifyStatusChange() {
419 if (!callback_.is_null())
420 callback_.Run();
423 CloudPolicyCoreStatusProvider::CloudPolicyCoreStatusProvider(
424 policy::CloudPolicyCore* core) : core_(core) {
425 core_->store()->AddObserver(this);
426 // TODO(bartfab): Add an observer that watches for client errors. Observing
427 // core_->client() directly is not safe as the client may be destroyed and
428 // (re-)created anytime if the user signs in or out on desktop platforms.
431 CloudPolicyCoreStatusProvider::~CloudPolicyCoreStatusProvider() {
432 core_->store()->RemoveObserver(this);
435 void CloudPolicyCoreStatusProvider::OnStoreLoaded(
436 policy::CloudPolicyStore* store) {
437 NotifyStatusChange();
440 void CloudPolicyCoreStatusProvider::OnStoreError(
441 policy::CloudPolicyStore* store) {
442 NotifyStatusChange();
445 UserPolicyStatusProvider::UserPolicyStatusProvider(
446 policy::CloudPolicyCore* core) : CloudPolicyCoreStatusProvider(core) {
449 UserPolicyStatusProvider::~UserPolicyStatusProvider() {
452 void UserPolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
453 if (!core_->store()->is_managed())
454 return;
455 GetStatusFromCore(core_, dict);
456 ExtractDomainFromUsername(dict);
459 #if defined(OS_CHROMEOS)
460 DevicePolicyStatusProvider::DevicePolicyStatusProvider(
461 policy::BrowserPolicyConnector* connector)
462 : CloudPolicyCoreStatusProvider(
463 connector->GetDeviceCloudPolicyManager()->core()) {
464 domain_ = connector->GetEnterpriseDomain();
467 DevicePolicyStatusProvider::~DevicePolicyStatusProvider() {
470 void DevicePolicyStatusProvider::GetStatus(base::DictionaryValue* dict) {
471 GetStatusFromCore(core_, dict);
472 dict->SetString("domain", domain_);
475 DeviceLocalAccountPolicyStatusProvider::DeviceLocalAccountPolicyStatusProvider(
476 const std::string& user_id,
477 policy::DeviceLocalAccountPolicyService* service)
478 : user_id_(user_id),
479 service_(service) {
480 service_->AddObserver(this);
483 DeviceLocalAccountPolicyStatusProvider::
484 ~DeviceLocalAccountPolicyStatusProvider() {
485 service_->RemoveObserver(this);
488 void DeviceLocalAccountPolicyStatusProvider::GetStatus(
489 base::DictionaryValue* dict) {
490 const policy::DeviceLocalAccountPolicyBroker* broker =
491 service_->GetBrokerForUser(user_id_);
492 if (broker) {
493 GetStatusFromCore(broker->core(), dict);
494 } else {
495 dict->SetBoolean("error", true);
496 dict->SetString("status",
497 policy::FormatStoreStatus(
498 policy::CloudPolicyStore::STATUS_BAD_STATE,
499 policy::CloudPolicyValidatorBase::VALIDATION_OK));
500 dict->SetString("username", std::string());
502 ExtractDomainFromUsername(dict);
503 dict->SetBoolean("publicAccount", true);
506 void DeviceLocalAccountPolicyStatusProvider::OnPolicyUpdated(
507 const std::string& user_id) {
508 if (user_id == user_id_)
509 NotifyStatusChange();
512 void DeviceLocalAccountPolicyStatusProvider::OnDeviceLocalAccountsChanged() {
513 NotifyStatusChange();
515 #endif
517 PolicyUIHandler::PolicyUIHandler()
518 : initialized_(false),
519 weak_factory_(this) {
522 PolicyUIHandler::~PolicyUIHandler() {
523 GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_CHROME, this);
524 GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
527 void PolicyUIHandler::RegisterMessages() {
528 #if defined(OS_CHROMEOS)
529 policy::BrowserPolicyConnector* connector =
530 g_browser_process->browser_policy_connector();
531 if (connector->IsEnterpriseManaged())
532 device_status_provider_.reset(new DevicePolicyStatusProvider(connector));
534 const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
535 if (user_manager->IsLoggedInAsPublicAccount()) {
536 policy::DeviceLocalAccountPolicyService* local_account_service =
537 connector->GetDeviceLocalAccountPolicyService();
538 if (local_account_service) {
539 user_status_provider_.reset(
540 new DeviceLocalAccountPolicyStatusProvider(
541 user_manager->GetLoggedInUser()->email(), local_account_service));
543 } else {
544 policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
545 policy::UserCloudPolicyManagerFactoryChromeOS::GetForProfile(
546 Profile::FromWebUI(web_ui()));
547 if (user_cloud_policy_manager) {
548 user_status_provider_.reset(
549 new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
552 #else
553 policy::UserCloudPolicyManager* user_cloud_policy_manager =
554 policy::UserCloudPolicyManagerFactory::GetForBrowserContext(
555 web_ui()->GetWebContents()->GetBrowserContext());
556 if (user_cloud_policy_manager) {
557 user_status_provider_.reset(
558 new UserPolicyStatusProvider(user_cloud_policy_manager->core()));
560 #endif
562 if (!user_status_provider_.get())
563 user_status_provider_.reset(new CloudPolicyStatusProvider());
564 if (!device_status_provider_.get())
565 device_status_provider_.reset(new CloudPolicyStatusProvider());
567 base::Closure update_callback(base::Bind(&PolicyUIHandler::SendStatus,
568 base::Unretained(this)));
569 user_status_provider_->SetStatusChangeCallback(update_callback);
570 device_status_provider_->SetStatusChangeCallback(update_callback);
571 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_CHROME, this);
572 GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
574 registrar_.Add(this,
575 chrome::NOTIFICATION_EXTENSION_LOADED,
576 content::NotificationService::AllSources());
577 registrar_.Add(this,
578 chrome::NOTIFICATION_EXTENSION_UNLOADED,
579 content::NotificationService::AllSources());
581 web_ui()->RegisterMessageCallback(
582 "initialized",
583 base::Bind(&PolicyUIHandler::HandleInitialized, base::Unretained(this)));
584 web_ui()->RegisterMessageCallback(
585 "reloadPolicies",
586 base::Bind(&PolicyUIHandler::HandleReloadPolicies,
587 base::Unretained(this)));
590 void PolicyUIHandler::Observe(int type,
591 const content::NotificationSource& source,
592 const content::NotificationDetails& details) {
593 DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED ||
594 type == chrome::NOTIFICATION_EXTENSION_UNLOADED);
595 SendPolicyNames();
596 SendPolicyValues();
599 void PolicyUIHandler::OnPolicyUpdated(const policy::PolicyNamespace& ns,
600 const policy::PolicyMap& previous,
601 const policy::PolicyMap& current) {
602 SendPolicyValues();
605 void PolicyUIHandler::SendPolicyNames() const {
606 base::DictionaryValue names;
608 Profile* profile = Profile::FromWebUI(web_ui());
609 policy::SchemaRegistry* registry =
610 policy::SchemaRegistryServiceFactory::GetForContext(
611 profile->GetOriginalProfile());
612 scoped_refptr<policy::SchemaMap> schema_map = registry->schema_map();
614 // Add Chrome policy names.
615 base::DictionaryValue* chrome_policy_names = new base::DictionaryValue;
616 policy::PolicyNamespace chrome_ns(policy::POLICY_DOMAIN_CHROME, "");
617 const policy::Schema* chrome_schema = schema_map->GetSchema(chrome_ns);
618 for (policy::Schema::Iterator it = chrome_schema->GetPropertiesIterator();
619 !it.IsAtEnd(); it.Advance()) {
620 chrome_policy_names->SetBoolean(it.key(), true);
622 names.Set("chromePolicyNames", chrome_policy_names);
624 #if !defined(OS_ANDROID) && !defined(OS_IOS)
625 // Add extension policy names.
626 base::DictionaryValue* extension_policy_names = new base::DictionaryValue;
628 extensions::ExtensionSystem* extension_system =
629 extensions::ExtensionSystem::Get(profile);
630 const extensions::ExtensionSet* extensions =
631 extension_system->extension_service()->extensions();
633 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
634 it != extensions->end(); ++it) {
635 const extensions::Extension* extension = it->get();
636 // Skip this extension if it's not an enterprise extension.
637 if (!extension->manifest()->HasPath(
638 extensions::manifest_keys::kStorageManagedSchema))
639 continue;
640 base::DictionaryValue* extension_value = new base::DictionaryValue;
641 extension_value->SetString("name", extension->name());
642 const policy::Schema* schema =
643 schema_map->GetSchema(policy::PolicyNamespace(
644 policy::POLICY_DOMAIN_EXTENSIONS, extension->id()));
645 base::DictionaryValue* policy_names = new base::DictionaryValue;
646 if (schema && schema->valid()) {
647 // Get policy names from the extension's policy schema.
648 // Store in a map, not an array, for faster lookup on JS side.
649 for (policy::Schema::Iterator prop = schema->GetPropertiesIterator();
650 !prop.IsAtEnd(); prop.Advance()) {
651 policy_names->SetBoolean(prop.key(), true);
654 extension_value->Set("policyNames", policy_names);
655 extension_policy_names->Set(extension->id(), extension_value);
657 names.Set("extensionPolicyNames", extension_policy_names);
658 #endif
660 web_ui()->CallJavascriptFunction("policy.Page.setPolicyNames", names);
663 void PolicyUIHandler::SendPolicyValues() const {
664 base::DictionaryValue all_policies;
666 // Add Chrome policy values.
667 base::DictionaryValue* chrome_policies = new base::DictionaryValue;
668 GetChromePolicyValues(chrome_policies);
669 all_policies.Set("chromePolicies", chrome_policies);
671 #if !defined(OS_ANDROID) && !defined(OS_IOS)
672 // Add extension policy values.
673 extensions::ExtensionSystem* extension_system =
674 extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()));
675 const extensions::ExtensionSet* extensions =
676 extension_system->extension_service()->extensions();
677 base::DictionaryValue* extension_values = new base::DictionaryValue;
679 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
680 it != extensions->end(); ++it) {
681 const extensions::Extension* extension = it->get();
682 // Skip this extension if it's not an enterprise extension.
683 if (!extension->manifest()->HasPath(
684 extensions::manifest_keys::kStorageManagedSchema))
685 continue;
686 base::DictionaryValue* extension_policies = new base::DictionaryValue;
687 policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
688 policy::POLICY_DOMAIN_EXTENSIONS, extension->id());
689 policy::PolicyErrorMap empty_error_map;
690 GetPolicyValues(GetPolicyService()->GetPolicies(policy_namespace),
691 &empty_error_map, extension_policies);
692 extension_values->Set(extension->id(), extension_policies);
694 all_policies.Set("extensionPolicies", extension_values);
695 #endif
696 web_ui()->CallJavascriptFunction("policy.Page.setPolicyValues", all_policies);
699 void PolicyUIHandler::GetPolicyValues(const policy::PolicyMap& map,
700 policy::PolicyErrorMap* errors,
701 base::DictionaryValue* values) const {
702 for (policy::PolicyMap::const_iterator entry = map.begin();
703 entry != map.end(); ++entry) {
704 base::DictionaryValue* value = new base::DictionaryValue;
705 value->Set("value", CopyAndConvert(entry->second.value).release());
706 if (entry->second.scope == policy::POLICY_SCOPE_USER)
707 value->SetString("scope", "user");
708 else
709 value->SetString("scope", "machine");
710 if (entry->second.level == policy::POLICY_LEVEL_RECOMMENDED)
711 value->SetString("level", "recommended");
712 else
713 value->SetString("level", "mandatory");
714 base::string16 error = errors->GetErrors(entry->first);
715 if (!error.empty())
716 value->SetString("error", error);
717 values->Set(entry->first, value);
721 void PolicyUIHandler::GetChromePolicyValues(
722 base::DictionaryValue* values) const {
723 policy::PolicyService* policy_service = GetPolicyService();
724 policy::PolicyMap map;
726 // Make a copy that can be modified, since some policy values are modified
727 // before being displayed.
728 map.CopyFrom(policy_service->GetPolicies(
729 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
731 // Get a list of all the errors in the policy values.
732 const policy::ConfigurationPolicyHandlerList* handler_list =
733 g_browser_process->browser_policy_connector()->GetHandlerList();
734 policy::PolicyErrorMap errors;
735 handler_list->ApplyPolicySettings(map, NULL, &errors);
737 // Convert dictionary values to strings for display.
738 handler_list->PrepareForDisplaying(&map);
740 GetPolicyValues(map, &errors, values);
743 void PolicyUIHandler::SendStatus() const {
744 scoped_ptr<base::DictionaryValue> device_status(new base::DictionaryValue);
745 device_status_provider_->GetStatus(device_status.get());
746 if (!device_domain_.empty())
747 device_status->SetString("domain", device_domain_);
748 scoped_ptr<base::DictionaryValue> user_status(new base::DictionaryValue);
749 user_status_provider_->GetStatus(user_status.get());
750 std::string username;
751 user_status->GetString("username", &username);
752 if (!username.empty())
753 user_status->SetString("domain", gaia::ExtractDomainName(username));
755 base::DictionaryValue status;
756 if (!device_status->empty())
757 status.Set("device", device_status.release());
758 if (!user_status->empty())
759 status.Set("user", user_status.release());
761 web_ui()->CallJavascriptFunction("policy.Page.setStatus", status);
764 void PolicyUIHandler::HandleInitialized(const base::ListValue* args) {
765 SendPolicyNames();
766 SendPolicyValues();
767 SendStatus();
770 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
771 GetPolicyService()->RefreshPolicies(
772 base::Bind(&PolicyUIHandler::OnRefreshPoliciesDone,
773 weak_factory_.GetWeakPtr()));
776 void PolicyUIHandler::OnRefreshPoliciesDone() const {
777 web_ui()->CallJavascriptFunction("policy.Page.reloadPoliciesDone");
780 policy::PolicyService* PolicyUIHandler::GetPolicyService() const {
781 return policy::ProfilePolicyConnectorFactory::GetForProfile(
782 Profile::FromWebUI(web_ui()))->policy_service();
785 PolicyUI::PolicyUI(content::WebUI* web_ui) : WebUIController(web_ui) {
786 web_ui->AddMessageHandler(new PolicyUIHandler);
787 content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
788 CreatePolicyUIHTMLSource());
791 PolicyUI::~PolicyUI() {