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