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