device_cloud_policy_invalidator.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
43class Profile;
44
45namespace policy {
46
47class 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
73DeviceCloudPolicyInvalidator::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
84DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
85    ~InvalidationServiceObserver() {
86  invalidation_service_->UnregisterInvalidationHandler(this);
87}
88
89invalidation::InvalidationService*
90DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
91    GetInvalidationService() {
92  return invalidation_service_;
93}
94
95bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
96         IsServiceConnected() const {
97  return is_service_connected_;
98}
99
100void 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
113void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
114    OnIncomingInvalidation(
115        const syncer::ObjectIdInvalidationMap& invalidation_map) {
116}
117
118std::string DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
119    GetOwnerName() const {
120  return "DevicePolicy";
121}
122
123DeviceCloudPolicyInvalidator::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
138DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
139  DestroyInvalidator();
140}
141
142void 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
173void 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
196void 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
213void 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
263void 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
277void 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
287void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() {
288  device_invalidation_service_observer_.reset();
289  device_invalidation_service_.reset();
290}
291
292}  // namespace policy
293