OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 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/chromeos/policy/cloud_external_data_policy_observer_chr omeos.h" | |
6 | |
7 #include <set> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/logging.h" | |
13 #include "base/values.h" | |
14 #include "chrome/browser/chrome_notification_types.h" | |
15 #include "chrome/browser/chromeos/login/user.h" | |
16 #include "chrome/browser/chromeos/login/user_manager.h" | |
17 #include "chrome/browser/chromeos/policy/device_local_account.h" | |
18 #include "chrome/browser/policy/cloud/cloud_policy_core.h" | |
19 #include "chrome/browser/policy/cloud/cloud_policy_store.h" | |
20 #include "chrome/browser/policy/policy_service.h" | |
21 #include "chrome/browser/policy/profile_policy_connector.h" | |
22 #include "chrome/browser/policy/profile_policy_connector_factory.h" | |
23 #include "chrome/browser/profiles/profile.h" | |
24 #include "chromeos/settings/cros_settings_names.h" | |
25 #include "chromeos/settings/cros_settings_provider.h" | |
26 #include "components/policy/core/common/external_data_fetcher.h" | |
27 #include "components/policy/core/common/policy_namespace.h" | |
28 #include "content/public/browser/notification_details.h" | |
29 #include "content/public/browser/notification_service.h" | |
30 #include "content/public/browser/notification_source.h" | |
31 | |
32 namespace policy { | |
33 | |
34 // Helper class that observes a policy for a logged-in user, notifying the | |
35 // |parent_| whenever the external data reference for this user changes. | |
36 class CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver | |
37 : public PolicyService::Observer { | |
38 public: | |
39 PolicyServiceObserver(CloudExternalDataPolicyObserverChromeOS* parent, | |
40 const std::string& user_id, | |
41 PolicyService* policy_service); | |
42 virtual ~PolicyServiceObserver(); | |
43 | |
44 // PolicyService::Observer: | |
45 virtual void OnPolicyUpdated(const PolicyNamespace& ns, | |
46 const PolicyMap& previous, | |
47 const PolicyMap& current) OVERRIDE; | |
48 | |
49 private: | |
50 CloudExternalDataPolicyObserverChromeOS* parent_; | |
51 const std::string user_id_; | |
52 PolicyService* policy_service_; | |
53 | |
54 DISALLOW_COPY_AND_ASSIGN(PolicyServiceObserver); | |
55 }; | |
56 | |
57 CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver:: | |
58 PolicyServiceObserver(CloudExternalDataPolicyObserverChromeOS* parent, | |
59 const std::string& user_id, | |
60 PolicyService* policy_service) | |
61 : parent_(parent), | |
62 user_id_(user_id), | |
63 policy_service_(policy_service) { | |
64 policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this); | |
65 | |
66 if (!IsDeviceLocalAccountUser(user_id, NULL)) { | |
67 // Notify |parent_| if the external data reference for |user_id_| is set | |
68 // during login. This is omitted for device-local accounts because their | |
69 // policy is available before login and the external data reference will | |
70 // have been seen by the |parent_| already. | |
71 const PolicyMap::Entry* entry = policy_service_->GetPolicies( | |
72 PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) | |
73 .Get(parent_->policy_); | |
74 if (entry) | |
75 parent_->HandleExternalDataPolicyUpdate(user_id_, entry); | |
76 } | |
77 } | |
78 | |
79 CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver:: | |
80 ~PolicyServiceObserver() { | |
81 policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this); | |
82 } | |
83 | |
84 void CloudExternalDataPolicyObserverChromeOS::PolicyServiceObserver:: | |
85 OnPolicyUpdated(const PolicyNamespace& ns, | |
86 const PolicyMap& previous, | |
87 const PolicyMap& current) { | |
88 DCHECK(ns == PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); | |
89 | |
90 const PolicyMap::Entry* previous_entry = previous.Get(parent_->policy_); | |
91 const PolicyMap::Entry* current_entry = current.Get(parent_->policy_); | |
92 if ((!previous_entry && current_entry) || | |
93 (previous_entry && !current_entry) || | |
94 (previous_entry && current_entry && | |
95 !previous_entry->Equals(*current_entry))) { | |
96 // Notify |parent_| if the external data reference for |user_id_| has | |
97 // changed. | |
98 parent_->HandleExternalDataPolicyUpdate(user_id_, current_entry); | |
99 } | |
100 } | |
101 | |
102 CloudExternalDataPolicyObserverChromeOS:: | |
103 CloudExternalDataPolicyObserverChromeOS( | |
104 chromeos::CrosSettings* cros_settings, | |
105 chromeos::UserManager* user_manager, | |
106 DeviceLocalAccountPolicyService* device_local_account_policy_service, | |
107 const std::string& policy) | |
108 : cros_settings_(cros_settings), | |
109 user_manager_(user_manager), | |
110 device_local_account_policy_service_(device_local_account_policy_service), | |
111 policy_(policy) { | |
112 notification_registrar_.Add( | |
113 this, | |
114 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, | |
115 content::NotificationService::AllSources()); | |
116 | |
117 if (device_local_account_policy_service_) | |
118 device_local_account_policy_service_->AddObserver(this); | |
119 | |
120 device_local_accounts_subscription_ = cros_settings_->AddSettingsObserver( | |
121 chromeos::kAccountsPrefDeviceLocalAccounts, | |
122 base::Bind( | |
123 &CloudExternalDataPolicyObserverChromeOS::RetrieveDeviceLocalAccounts, | |
124 base::Unretained(this))); | |
125 } | |
126 | |
127 CloudExternalDataPolicyObserverChromeOS:: | |
128 ~CloudExternalDataPolicyObserverChromeOS() { | |
129 } | |
130 | |
131 void CloudExternalDataPolicyObserverChromeOS::Init() { | |
132 RetrieveDeviceLocalAccounts(); | |
133 } | |
134 | |
135 void CloudExternalDataPolicyObserverChromeOS::Shutdown() { | |
136 device_local_accounts_subscription_.reset(); | |
137 if (device_local_account_policy_service_) | |
138 device_local_account_policy_service_->RemoveObserver(this); | |
139 notification_registrar_.RemoveAll(); | |
140 | |
141 for (DeviceLocalAccountEntryMap::iterator it = | |
142 device_local_account_entries_.begin(); | |
143 it != device_local_account_entries_.end(); ++it) { | |
144 delete it->second.value; | |
145 delete it->second.external_data_fetcher; | |
146 } | |
Joao da Silva
2013/11/27 14:33:59
device_local_account_entries_.clear()?
bartfab (slow)
2013/11/27 20:10:15
Done.
| |
147 logged_in_user_observers_.clear(); | |
148 } | |
149 | |
150 void CloudExternalDataPolicyObserverChromeOS::Observe( | |
151 int type, | |
152 const content::NotificationSource& source, | |
153 const content::NotificationDetails& details) { | |
154 if (type != chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) { | |
155 NOTREACHED(); | |
156 return; | |
157 } | |
158 Profile* profile = content::Details<Profile>(details).ptr(); | |
159 | |
160 const chromeos::User* user = user_manager_->GetUserByProfile(profile); | |
161 if (!user) { | |
162 NOTREACHED(); | |
163 return; | |
164 } | |
165 | |
166 const std::string& user_id = user->email(); | |
167 if (logged_in_user_observers_.find(user_id) != | |
168 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.
| |
169 NOTREACHED(); | |
170 return; | |
171 } | |
172 | |
173 ProfilePolicyConnector* policy_connector = | |
174 ProfilePolicyConnectorFactory::GetForProfile(profile); | |
175 logged_in_user_observers_[user_id] = make_linked_ptr( | |
176 new PolicyServiceObserver(this, | |
177 user_id, | |
178 policy_connector->policy_service())); | |
179 } | |
180 | |
181 void CloudExternalDataPolicyObserverChromeOS::OnPolicyUpdated( | |
182 const std::string& user_id) { | |
183 if (logged_in_user_observers_.find(user_id) != | |
184 logged_in_user_observers_.end()) { | |
Joao da Silva
2013/11/27 14:33:59
ContainsKey
bartfab (slow)
2013/11/27 20:10:15
Done.
| |
185 // When a device-local account is logged in, a policy change triggers both | |
186 // OnPolicyUpdated() and PolicyServiceObserver::OnPolicyUpdated(). Ignore | |
187 // the former so that the policy change is handled only once. | |
188 return; | |
189 } | |
190 | |
191 if (!device_local_account_policy_service_) { | |
192 NOTREACHED(); | |
193 return; | |
194 } | |
195 DeviceLocalAccountPolicyBroker* broker = | |
196 device_local_account_policy_service_->GetBrokerForUser(user_id); | |
197 if (!broker) { | |
198 NOTREACHED(); | |
199 return; | |
200 } | |
201 | |
202 const PolicyMap::Entry* entry = | |
203 broker->core()->store()->policy_map().Get(policy_); | |
204 if (!entry) { | |
205 DeviceLocalAccountEntryMap::iterator it = | |
206 device_local_account_entries_.find(user_id); | |
207 if (it != device_local_account_entries_.end()) { | |
208 delete it->second.value; | |
209 delete it->second.external_data_fetcher; | |
210 device_local_account_entries_.erase(it); | |
211 HandleExternalDataPolicyUpdate(user_id, NULL); | |
212 } | |
213 return; | |
214 } | |
215 | |
216 PolicyMap::Entry& map_entry = device_local_account_entries_[user_id]; | |
217 if (map_entry.Equals(*entry)) | |
218 return; | |
219 | |
220 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.
| |
221 HandleExternalDataPolicyUpdate(user_id, entry); | |
222 } | |
223 | |
224 void CloudExternalDataPolicyObserverChromeOS::OnDeviceLocalAccountsChanged() { | |
225 // No action needed here, changes to the list of device-local accounts get | |
226 // handled via the kAccountsPrefDeviceLocalAccounts device setting observer. | |
227 } | |
228 | |
229 void CloudExternalDataPolicyObserverChromeOS::RetrieveDeviceLocalAccounts() { | |
230 // Schedule a callback if device policy has not yet been verified. | |
231 if (chromeos::CrosSettingsProvider::TRUSTED != | |
232 cros_settings_->PrepareTrustedValues(base::Bind( | |
233 &CloudExternalDataPolicyObserverChromeOS::RetrieveDeviceLocalAccounts, | |
234 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
| |
235 return; | |
236 } | |
237 | |
238 std::vector<DeviceLocalAccount> device_local_account_list = | |
239 policy::GetDeviceLocalAccounts(cros_settings_); | |
240 std::set<std::string> device_local_accounts; | |
241 for (std::vector<DeviceLocalAccount>::const_iterator it = | |
242 device_local_account_list.begin(); | |
243 it != device_local_account_list.end(); ++it) { | |
244 device_local_accounts.insert(it->user_id); | |
245 } | |
246 | |
247 for (DeviceLocalAccountEntryMap::iterator it = | |
248 device_local_account_entries_.begin(); | |
249 it != device_local_account_entries_.end(); ) { | |
250 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.
| |
251 const std::string user_id = it->first; | |
252 delete it->second.value; | |
253 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.
| |
254 device_local_account_entries_.erase(it++); | |
255 // When a device-local account whose external data reference was set is | |
256 // removed, emit a notification that the external data reference has been | |
257 // cleared. | |
258 HandleExternalDataPolicyUpdate(user_id, NULL); | |
259 } else { | |
260 ++it; | |
261 } | |
262 } | |
263 | |
264 for (std::set<std::string>::const_iterator it = device_local_accounts.begin(); | |
265 it != device_local_accounts.end(); ++it) { | |
266 OnPolicyUpdated(*it); | |
267 } | |
268 } | |
269 | |
270 void CloudExternalDataPolicyObserverChromeOS::HandleExternalDataPolicyUpdate( | |
271 const std::string& user_id, | |
272 const PolicyMap::Entry* entry) { | |
273 if (!entry) { | |
274 OnExternalDataCleared(user_id); | |
275 fetch_weak_ptrs_.erase(user_id); | |
276 return; | |
277 } | |
278 | |
279 OnExternalDataSet(user_id); | |
280 | |
281 linked_ptr<WeakPtrFactory>& weak_ptr_factory = fetch_weak_ptrs_[user_id]; | |
282 weak_ptr_factory.reset(new WeakPtrFactory(this)); | |
283 if (entry->external_data_fetcher) { | |
284 entry->external_data_fetcher->Fetch(base::Bind( | |
285 &CloudExternalDataPolicyObserverChromeOS::OnExternalDataFetched, | |
286 weak_ptr_factory->GetWeakPtr(), | |
287 user_id)); | |
288 } else { | |
289 NOTREACHED(); | |
290 } | |
291 } | |
292 | |
293 } // namespace policy | |
OLD | NEW |