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