Chromium Code Reviews| Index: chrome/browser/chromeos/policy/cloud_external_data_policy_observer_chromeos.cc |
| diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_chromeos.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_chromeos.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ff69d60ddfac1d964870cf0d3f09fbfe001b52b7 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_chromeos.cc |
| @@ -0,0 +1,293 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/chromeos/policy/cloud_external_data_policy_observer_chromeos.h" |
| + |
| +#include <set> |
| +#include <vector> |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| +#include "base/logging.h" |
| +#include "base/values.h" |
| +#include "chrome/browser/chrome_notification_types.h" |
| +#include "chrome/browser/chromeos/login/user.h" |
| +#include "chrome/browser/chromeos/login/user_manager.h" |
| +#include "chrome/browser/chromeos/policy/device_local_account.h" |
| +#include "chrome/browser/policy/cloud/cloud_policy_core.h" |
| +#include "chrome/browser/policy/cloud/cloud_policy_store.h" |
| +#include "chrome/browser/policy/policy_service.h" |
| +#include "chrome/browser/policy/profile_policy_connector.h" |
| +#include "chrome/browser/policy/profile_policy_connector_factory.h" |
| +#include "chrome/browser/profiles/profile.h" |
| +#include "chromeos/settings/cros_settings_names.h" |
| +#include "chromeos/settings/cros_settings_provider.h" |
| +#include "components/policy/core/common/external_data_fetcher.h" |
| +#include "components/policy/core/common/policy_namespace.h" |
| +#include "content/public/browser/notification_details.h" |
| +#include "content/public/browser/notification_service.h" |
| +#include "content/public/browser/notification_source.h" |
| + |
| +namespace policy { |
| + |
| +// Helper class that observes a policy for a logged-in user, notifying the |
| +// |parent_| whenever the external data reference for this user changes. |
| +class CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver |
| + : public PolicyService::Observer { |
| + public: |
| + PolicyServiceObserver(CloudExternalDataPolicyObserverChromeOS* parent, |
| + const std::string& user_id, |
| + PolicyService* policy_service); |
| + virtual ~PolicyServiceObserver(); |
| + |
| + // PolicyService::Observer: |
| + virtual void OnPolicyUpdated(const PolicyNamespace& ns, |
| + const PolicyMap& previous, |
| + const PolicyMap& current) OVERRIDE; |
| + |
| + private: |
| + CloudExternalDataPolicyObserverChromeOS* parent_; |
| + const std::string user_id_; |
| + PolicyService* policy_service_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PolicyServiceObserver); |
| +}; |
| + |
| +CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver:: |
| + PolicyServiceObserver(CloudExternalDataPolicyObserverChromeOS* parent, |
| + const std::string& user_id, |
| + PolicyService* policy_service) |
| + : parent_(parent), |
| + user_id_(user_id), |
| + policy_service_(policy_service) { |
| + policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this); |
| + |
| + if (!IsDeviceLocalAccountUser(user_id, NULL)) { |
| + // Notify |parent_| if the external data reference for |user_id_| is set |
| + // during login. This is omitted for device-local accounts because their |
| + // policy is available before login and the external data reference will |
| + // have been seen by the |parent_| already. |
| + const PolicyMap::Entry* entry = policy_service_->GetPolicies( |
| + PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) |
| + .Get(parent_->policy_); |
| + if (entry) |
| + parent_->HandleExternalDataPolicyUpdate(user_id_, entry); |
| + } |
| +} |
| + |
| +CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver:: |
| + ~PolicyServiceObserver() { |
| + policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this); |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver:: |
| + OnPolicyUpdated(const PolicyNamespace& ns, |
| + const PolicyMap& previous, |
| + const PolicyMap& current) { |
| + DCHECK(ns == PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); |
| + |
| + const PolicyMap::Entry* previous_entry = previous.Get(parent_->policy_); |
| + const PolicyMap::Entry* current_entry = current.Get(parent_->policy_); |
| + if ((!previous_entry && current_entry) || |
| + (previous_entry && !current_entry) || |
| + (previous_entry && current_entry && |
| + !previous_entry->Equals(*current_entry))) { |
| + // Notify |parent_| if the external data reference for |user_id_| has |
| + // changed. |
| + parent_->HandleExternalDataPolicyUpdate(user_id_, current_entry); |
| + } |
| +} |
| + |
| +CloudExternalDataPolicyObserverChromeOS:: |
| + CloudExternalDataPolicyObserverChromeOS( |
| + chromeos::CrosSettings* cros_settings, |
| + chromeos::UserManager* user_manager, |
| + DeviceLocalAccountPolicyService* device_local_account_policy_service, |
| + const std::string& policy) |
| + : cros_settings_(cros_settings), |
| + user_manager_(user_manager), |
| + device_local_account_policy_service_(device_local_account_policy_service), |
| + policy_(policy) { |
| + notification_registrar_.Add( |
| + this, |
| + chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, |
| + content::NotificationService::AllSources()); |
| + |
| + if (device_local_account_policy_service_) |
| + device_local_account_policy_service_->AddObserver(this); |
| + |
| + device_local_accounts_subscription_ = cros_settings_->AddSettingsObserver( |
| + chromeos::kAccountsPrefDeviceLocalAccounts, |
| + base::Bind( |
| + &CloudExternalDataPolicyObserverChromeOS::RetrieveDeviceLocalAccounts, |
| + base::Unretained(this))); |
| +} |
| + |
| +CloudExternalDataPolicyObserverChromeOS:: |
| + ~CloudExternalDataPolicyObserverChromeOS() { |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::Init() { |
| + RetrieveDeviceLocalAccounts(); |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::Shutdown() { |
| + device_local_accounts_subscription_.reset(); |
| + if (device_local_account_policy_service_) |
| + device_local_account_policy_service_->RemoveObserver(this); |
| + notification_registrar_.RemoveAll(); |
| + |
| + for (DeviceLocalAccountEntryMap::iterator it = |
| + device_local_account_entries_.begin(); |
| + it != device_local_account_entries_.end(); ++it) { |
| + delete it->second.value; |
| + delete it->second.external_data_fetcher; |
| + } |
|
Joao da Silva
2013/11/27 14:33:59
device_local_account_entries_.clear()?
bartfab (slow)
2013/11/27 20:10:15
Done.
|
| + logged_in_user_observers_.clear(); |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::Observe( |
| + int type, |
| + const content::NotificationSource& source, |
| + const content::NotificationDetails& details) { |
| + if (type != chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + Profile* profile = content::Details<Profile>(details).ptr(); |
| + |
| + const chromeos::User* user = user_manager_->GetUserByProfile(profile); |
| + if (!user) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + const std::string& user_id = user->email(); |
| + if (logged_in_user_observers_.find(user_id) != |
| + logged_in_user_observers_.end()) { |
|
Joao da Silva
2013/11/27 14:33:59
ContainsKey() is clearer
bartfab (slow)
2013/11/27 20:10:15
Done.
|
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + ProfilePolicyConnector* policy_connector = |
| + ProfilePolicyConnectorFactory::GetForProfile(profile); |
| + logged_in_user_observers_[user_id] = make_linked_ptr( |
| + new PolicyServiceObserver(this, |
| + user_id, |
| + policy_connector->policy_service())); |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::OnPolicyUpdated( |
| + const std::string& user_id) { |
| + if (logged_in_user_observers_.find(user_id) != |
| + logged_in_user_observers_.end()) { |
|
Joao da Silva
2013/11/27 14:33:59
ContainsKey
bartfab (slow)
2013/11/27 20:10:15
Done.
|
| + // When a device-local account is logged in, a policy change triggers both |
| + // OnPolicyUpdated() and PolicyServiceObserver::OnPolicyUpdated(). Ignore |
| + // the former so that the policy change is handled only once. |
| + return; |
| + } |
| + |
| + if (!device_local_account_policy_service_) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + DeviceLocalAccountPolicyBroker* broker = |
| + device_local_account_policy_service_->GetBrokerForUser(user_id); |
| + if (!broker) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + const PolicyMap::Entry* entry = |
| + broker->core()->store()->policy_map().Get(policy_); |
| + if (!entry) { |
| + DeviceLocalAccountEntryMap::iterator it = |
| + device_local_account_entries_.find(user_id); |
| + if (it != device_local_account_entries_.end()) { |
| + delete it->second.value; |
| + delete it->second.external_data_fetcher; |
| + device_local_account_entries_.erase(it); |
| + HandleExternalDataPolicyUpdate(user_id, NULL); |
| + } |
| + return; |
| + } |
| + |
| + PolicyMap::Entry& map_entry = device_local_account_entries_[user_id]; |
| + if (map_entry.Equals(*entry)) |
| + return; |
| + |
| + map_entry = *entry->DeepCopy(); |
|
Joao da Silva
2013/11/27 14:33:59
This leaks map_entry.value and map_entry.external_
bartfab (slow)
2013/11/27 20:10:15
Done.
|
| + HandleExternalDataPolicyUpdate(user_id, entry); |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::OnDeviceLocalAccountsChanged() { |
| + // No action needed here, changes to the list of device-local accounts get |
| + // handled via the kAccountsPrefDeviceLocalAccounts device setting observer. |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::RetrieveDeviceLocalAccounts() { |
| + // Schedule a callback if device policy has not yet been verified. |
| + if (chromeos::CrosSettingsProvider::TRUSTED != |
| + cros_settings_->PrepareTrustedValues(base::Bind( |
| + &CloudExternalDataPolicyObserverChromeOS::RetrieveDeviceLocalAccounts, |
| + base::Unretained(this)))) { |
|
Joao da Silva
2013/11/27 14:33:59
Is it safe to pass an unretained this? Can't the c
bartfab (slow)
2013/11/27 20:10:15
Nice catch. I copy & pasted this snippet from some
|
| + return; |
| + } |
| + |
| + std::vector<DeviceLocalAccount> device_local_account_list = |
| + policy::GetDeviceLocalAccounts(cros_settings_); |
| + std::set<std::string> device_local_accounts; |
| + for (std::vector<DeviceLocalAccount>::const_iterator it = |
| + device_local_account_list.begin(); |
| + it != device_local_account_list.end(); ++it) { |
| + device_local_accounts.insert(it->user_id); |
| + } |
| + |
| + for (DeviceLocalAccountEntryMap::iterator it = |
| + device_local_account_entries_.begin(); |
| + it != device_local_account_entries_.end(); ) { |
| + if (device_local_accounts.find(it->first) == device_local_accounts.end()) { |
|
Joao da Silva
2013/11/27 14:33:59
!ContainsKey
bartfab (slow)
2013/11/27 20:10:15
Done.
|
| + const std::string user_id = it->first; |
| + delete it->second.value; |
| + delete it->second.external_data_fetcher; |
|
Joao da Silva
2013/11/27 14:33:59
This is repeated in 3 places, and maybe a 4th is a
bartfab (slow)
2013/11/27 20:10:15
Done.
|
| + device_local_account_entries_.erase(it++); |
| + // When a device-local account whose external data reference was set is |
| + // removed, emit a notification that the external data reference has been |
| + // cleared. |
| + HandleExternalDataPolicyUpdate(user_id, NULL); |
| + } else { |
| + ++it; |
| + } |
| + } |
| + |
| + for (std::set<std::string>::const_iterator it = device_local_accounts.begin(); |
| + it != device_local_accounts.end(); ++it) { |
| + OnPolicyUpdated(*it); |
| + } |
| +} |
| + |
| +void CloudExternalDataPolicyObserverChromeOS::HandleExternalDataPolicyUpdate( |
| + const std::string& user_id, |
| + const PolicyMap::Entry* entry) { |
| + if (!entry) { |
| + OnExternalDataCleared(user_id); |
| + fetch_weak_ptrs_.erase(user_id); |
| + return; |
| + } |
| + |
| + OnExternalDataSet(user_id); |
| + |
| + linked_ptr<WeakPtrFactory>& weak_ptr_factory = fetch_weak_ptrs_[user_id]; |
| + weak_ptr_factory.reset(new WeakPtrFactory(this)); |
| + if (entry->external_data_fetcher) { |
| + entry->external_data_fetcher->Fetch(base::Bind( |
| + &CloudExternalDataPolicyObserverChromeOS::OnExternalDataFetched, |
| + weak_ptr_factory->GetWeakPtr(), |
| + user_id)); |
| + } else { |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +} // namespace policy |