Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / policy / device_cloud_policy_invalidator.cc
1 // Copyright 2014 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/device_cloud_policy_invalidator.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/time/clock.h"
13 #include "base/time/default_clock.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/browser_process_platform_part_chromeos.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
19 #include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h"
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #include "chrome/browser/chromeos/settings/device_identity_provider.h"
22 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
23 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
24 #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/common/chrome_content_client.h"
27 #include "components/invalidation/invalidation_handler.h"
28 #include "components/invalidation/invalidation_service.h"
29 #include "components/invalidation/invalidation_state_tracker.h"
30 #include "components/invalidation/invalidator_state.h"
31 #include "components/invalidation/invalidator_storage.h"
32 #include "components/invalidation/profile_invalidation_provider.h"
33 #include "components/invalidation/ticl_invalidation_service.h"
34 #include "components/invalidation/ticl_settings_provider.h"
35 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
36 #include "components/user_manager/user.h"
37 #include "content/public/browser/notification_details.h"
38 #include "content/public/browser/notification_service.h"
39 #include "google_apis/gaia/identity_provider.h"
40 #include "net/url_request/url_request_context_getter.h"
41 #include "policy/proto/device_management_backend.pb.h"
42
43 class Profile;
44
45 namespace policy {
46
47 class DeviceCloudPolicyInvalidator::InvalidationServiceObserver
48     : public syncer::InvalidationHandler {
49  public:
50   explicit InvalidationServiceObserver(
51       DeviceCloudPolicyInvalidator* parent,
52       invalidation::InvalidationService* invalidation_service);
53   virtual ~InvalidationServiceObserver();
54
55   invalidation::InvalidationService* GetInvalidationService();
56   bool IsServiceConnected() const;
57
58   // public syncer::InvalidationHandler:
59   virtual void OnInvalidatorStateChange(
60       syncer::InvalidatorState state) OVERRIDE;
61   virtual void OnIncomingInvalidation(
62       const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
63   virtual std::string GetOwnerName() const OVERRIDE;
64
65  private:
66   DeviceCloudPolicyInvalidator* parent_;
67   invalidation::InvalidationService* invalidation_service_;
68   bool is_service_connected_;
69
70   DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
71 };
72
73 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
74     InvalidationServiceObserver(
75         DeviceCloudPolicyInvalidator* parent,
76         invalidation::InvalidationService* invalidation_service)
77     : parent_(parent),
78       invalidation_service_(invalidation_service),
79       is_service_connected_(invalidation_service->GetInvalidatorState() ==
80                                 syncer::INVALIDATIONS_ENABLED) {
81   invalidation_service_->RegisterInvalidationHandler(this);
82 }
83
84 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
85     ~InvalidationServiceObserver() {
86   invalidation_service_->UnregisterInvalidationHandler(this);
87 }
88
89 invalidation::InvalidationService*
90 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
91     GetInvalidationService() {
92   return invalidation_service_;
93 }
94
95 bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
96          IsServiceConnected() const {
97   return is_service_connected_;
98 }
99
100 void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
101     OnInvalidatorStateChange(syncer::InvalidatorState state) {
102   const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
103   if (is_service_connected == is_service_connected_)
104     return;
105
106   is_service_connected_ = is_service_connected;
107   if (is_service_connected_)
108     parent_->OnInvalidationServiceConnected(invalidation_service_);
109   else
110     parent_->OnInvalidationServiceDisconnected(invalidation_service_);
111 }
112
113 void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
114     OnIncomingInvalidation(
115         const syncer::ObjectIdInvalidationMap& invalidation_map) {
116 }
117
118 std::string DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
119     GetOwnerName() const {
120   return "DevicePolicy";
121 }
122
123 DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator()
124     : invalidation_service_(NULL),
125       highest_handled_invalidation_version_(0) {
126   // The DeviceCloudPolicyInvalidator should be created before any user
127   // Profiles.
128   DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
129
130   // Subscribe to notification about new user profiles becoming available.
131   registrar_.Add(this,
132                  chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
133                  content::NotificationService::AllSources());
134
135   TryToCreateInvalidator();
136 }
137
138 DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
139   DestroyInvalidator();
140 }
141
142 void DeviceCloudPolicyInvalidator::Observe(
143     int type,
144     const content::NotificationSource& source,
145     const content::NotificationDetails& details) {
146   DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type);
147   Profile* profile = content::Details<Profile>(details).ptr();
148   invalidation::ProfileInvalidationProvider* invalidation_provider =
149       invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile);
150   if (!invalidation_provider) {
151     // If the Profile does not support invalidation (e.g. guest, incognito),
152     // ignore it.
153     return;
154   }
155   user_manager::User* user =
156       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
157   if (!user ||
158       g_browser_process->platform_part()->browser_policy_connector_chromeos()->
159           GetUserAffiliation(user->email()) != USER_AFFILIATION_MANAGED) {
160     // If the Profile belongs to a user who is not affiliated with the domain
161     // the device is enrolled into, ignore it.
162     return;
163   }
164   // Create a state observer for the user's invalidation service.
165   profile_invalidation_service_observers_.push_back(
166       new InvalidationServiceObserver(
167               this,
168               invalidation_provider->GetInvalidationService()));
169
170   TryToCreateInvalidator();
171 }
172
173 void DeviceCloudPolicyInvalidator::OnInvalidationServiceConnected(
174     invalidation::InvalidationService* invalidation_service) {
175   if (!device_invalidation_service_) {
176     // The lack of a device-global invalidation service implies that a
177     // |CloudPolicyInvalidator| backed by another connected service exists
178     // already. There is no need to switch from that to the service which just
179     // connected.
180     return;
181   }
182
183   if (invalidation_service != device_invalidation_service_.get()) {
184     // If an invalidation service other than the device-global one connected,
185     // destroy the device-global service and the |CloudPolicyInvalidator| backed
186     // by it, if any.
187     DestroyInvalidator();
188     DestroyDeviceInvalidationService();
189   }
190
191   // Create a |CloudPolicyInvalidator| backed by the invalidation service which
192   // just connected.
193   CreateInvalidator(invalidation_service);
194 }
195
196 void DeviceCloudPolicyInvalidator::OnInvalidationServiceDisconnected(
197     invalidation::InvalidationService* invalidation_service) {
198   if (invalidation_service != invalidation_service_) {
199     // If the invalidation service which disconnected is not backing the current
200     // |CloudPolicyInvalidator|, return.
201     return;
202   }
203
204   // Destroy the |CloudPolicyInvalidator| backed by the invalidation service
205   // which just disconnected.
206   DestroyInvalidator();
207
208   // Try to create a |CloudPolicyInvalidator| backed by another invalidation
209   // service.
210   TryToCreateInvalidator();
211 }
212
213 void DeviceCloudPolicyInvalidator::TryToCreateInvalidator() {
214   if (invalidator_) {
215     // If a |CloudPolicyInvalidator| exists already, return.
216     return;
217   }
218
219   for (ScopedVector<InvalidationServiceObserver>::const_iterator it =
220            profile_invalidation_service_observers_.begin();
221            it != profile_invalidation_service_observers_.end(); ++it) {
222     if ((*it)->IsServiceConnected()) {
223       // If a connected invalidation service belonging to an affiliated
224       // logged-in user is found, create a |CloudPolicyInvalidator| backed by
225       // that service and destroy the device-global service, if any.
226       DestroyDeviceInvalidationService();
227       CreateInvalidator((*it)->GetInvalidationService());
228       return;
229     }
230   }
231
232   if (!device_invalidation_service_) {
233     // If no other connected invalidation service was found, ensure that a
234     // device-global service is running.
235     device_invalidation_service_.reset(
236         new invalidation::TiclInvalidationService(
237             GetUserAgent(),
238             scoped_ptr<IdentityProvider>(new chromeos::DeviceIdentityProvider(
239                 chromeos::DeviceOAuth2TokenServiceFactory::Get())),
240             scoped_ptr<invalidation::TiclSettingsProvider>(
241                 new TiclDeviceSettingsProvider),
242             g_browser_process->gcm_driver(),
243             g_browser_process->system_request_context()));
244     device_invalidation_service_->Init(
245         scoped_ptr<syncer::InvalidationStateTracker>(
246             new invalidation::InvalidatorStorage(
247                     g_browser_process->local_state())));
248     device_invalidation_service_observer_.reset(
249         new InvalidationServiceObserver(
250                 this,
251                 device_invalidation_service_.get()));
252   }
253
254   if (device_invalidation_service_observer_->IsServiceConnected()) {
255     // If the device-global invalidation service is connected, create a
256     // |CloudPolicyInvalidator| backed by it. Otherwise,  a
257     // |CloudPolicyInvalidator| will be created later when a connected service
258     // becomes available.
259     CreateInvalidator(device_invalidation_service_.get());
260   }
261 }
262
263 void DeviceCloudPolicyInvalidator::CreateInvalidator(
264     invalidation::InvalidationService* invalidation_service) {
265   invalidation_service_ = invalidation_service;
266   DCHECK(!invalidator_);
267   invalidator_.reset(new CloudPolicyInvalidator(
268       enterprise_management::DeviceRegisterRequest::DEVICE,
269       g_browser_process->platform_part()->browser_policy_connector_chromeos()->
270           GetDeviceCloudPolicyManager()->core(),
271       base::MessageLoopProxy::current(),
272       scoped_ptr<base::Clock>(new base::DefaultClock()),
273       highest_handled_invalidation_version_));
274   invalidator_->Initialize(invalidation_service);
275 }
276
277 void DeviceCloudPolicyInvalidator::DestroyInvalidator() {
278   if (invalidator_) {
279     highest_handled_invalidation_version_ =
280         invalidator_->highest_handled_invalidation_version();
281     invalidator_->Shutdown();
282   }
283   invalidator_.reset();
284   invalidation_service_ = NULL;
285 }
286
287 void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() {
288   device_invalidation_service_observer_.reset();
289   device_invalidation_service_.reset();
290 }
291
292 }  // namespace policy