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.
5 #include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
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"
47 class DeviceCloudPolicyInvalidator::InvalidationServiceObserver
48 : public syncer::InvalidationHandler
{
50 explicit InvalidationServiceObserver(
51 DeviceCloudPolicyInvalidator
* parent
,
52 invalidation::InvalidationService
* invalidation_service
);
53 virtual ~InvalidationServiceObserver();
55 invalidation::InvalidationService
* GetInvalidationService();
56 bool IsServiceConnected() const;
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
;
66 DeviceCloudPolicyInvalidator
* parent_
;
67 invalidation::InvalidationService
* invalidation_service_
;
68 bool is_service_connected_
;
70 DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver
);
73 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
74 InvalidationServiceObserver(
75 DeviceCloudPolicyInvalidator
* parent
,
76 invalidation::InvalidationService
* invalidation_service
)
78 invalidation_service_(invalidation_service
),
79 is_service_connected_(invalidation_service
->GetInvalidatorState() ==
80 syncer::INVALIDATIONS_ENABLED
) {
81 invalidation_service_
->RegisterInvalidationHandler(this);
84 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
85 ~InvalidationServiceObserver() {
86 invalidation_service_
->UnregisterInvalidationHandler(this);
89 invalidation::InvalidationService
*
90 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
91 GetInvalidationService() {
92 return invalidation_service_
;
95 bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
96 IsServiceConnected() const {
97 return is_service_connected_
;
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_
)
106 is_service_connected_
= is_service_connected
;
107 if (is_service_connected_
)
108 parent_
->OnInvalidationServiceConnected(invalidation_service_
);
110 parent_
->OnInvalidationServiceDisconnected(invalidation_service_
);
113 void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
114 OnIncomingInvalidation(
115 const syncer::ObjectIdInvalidationMap
& invalidation_map
) {
118 std::string
DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
119 GetOwnerName() const {
120 return "DevicePolicy";
123 DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator()
124 : invalidation_service_(NULL
),
125 highest_handled_invalidation_version_(0) {
126 // The DeviceCloudPolicyInvalidator should be created before any user
128 DCHECK(g_browser_process
->profile_manager()->GetLoadedProfiles().empty());
130 // Subscribe to notification about new user profiles becoming available.
132 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
133 content::NotificationService::AllSources());
135 TryToCreateInvalidator();
138 DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
139 DestroyInvalidator();
142 void DeviceCloudPolicyInvalidator::Observe(
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),
155 user_manager::User
* user
=
156 chromeos::ProfileHelper::Get()->GetUserByProfile(profile
);
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.
164 // Create a state observer for the user's invalidation service.
165 profile_invalidation_service_observers_
.push_back(
166 new InvalidationServiceObserver(
168 invalidation_provider
->GetInvalidationService()));
170 TryToCreateInvalidator();
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
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
187 DestroyInvalidator();
188 DestroyDeviceInvalidationService();
191 // Create a |CloudPolicyInvalidator| backed by the invalidation service which
193 CreateInvalidator(invalidation_service
);
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.
204 // Destroy the |CloudPolicyInvalidator| backed by the invalidation service
205 // which just disconnected.
206 DestroyInvalidator();
208 // Try to create a |CloudPolicyInvalidator| backed by another invalidation
210 TryToCreateInvalidator();
213 void DeviceCloudPolicyInvalidator::TryToCreateInvalidator() {
215 // If a |CloudPolicyInvalidator| exists already, return.
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());
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(
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(
251 device_invalidation_service_
.get()));
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());
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
);
277 void DeviceCloudPolicyInvalidator::DestroyInvalidator() {
279 highest_handled_invalidation_version_
=
280 invalidator_
->highest_handled_invalidation_version();
281 invalidator_
->Shutdown();
283 invalidator_
.reset();
284 invalidation_service_
= NULL
;
287 void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() {
288 device_invalidation_service_observer_
.reset();
289 device_invalidation_service_
.reset();
292 } // namespace policy