| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/policy/device_token_fetcher.h" | 5 #include "chrome/browser/policy/device_token_fetcher.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/path_service.h" | 8 #include "chrome/browser/policy/cloud_policy_cache.h" |
| 9 #include "base/singleton.h" | 9 #include "chrome/browser/policy/device_management_service.h" |
| 10 #include "base/string_util.h" | |
| 11 #include "chrome/browser/net/gaia/token_service.h" | |
| 12 #include "chrome/browser/policy/proto/device_management_local.pb.h" | 10 #include "chrome/browser/policy/proto/device_management_local.pb.h" |
| 13 #include "chrome/browser/profiles/profile.h" | |
| 14 #include "chrome/common/chrome_paths.h" | |
| 15 #include "chrome/common/guid.h" | |
| 16 #include "chrome/common/net/gaia/gaia_constants.h" | |
| 17 #include "chrome/common/notification_details.h" | |
| 18 #include "chrome/common/notification_service.h" | |
| 19 #include "chrome/common/notification_source.h" | |
| 20 #include "chrome/common/notification_type.h" | |
| 21 | |
| 22 #if defined(OS_CHROMEOS) | |
| 23 #include "chrome/browser/chromeos/login/user_manager.h" | |
| 24 #else | |
| 25 #include "chrome/browser/browser_signin.h" | |
| 26 #endif | |
| 27 | 11 |
| 28 namespace { | 12 namespace { |
| 29 | 13 |
| 30 // Domain names that are known not to be managed. | 14 // Retry after 3 seconds (with exponential backoff) after token fetch errors. |
| 31 // We don't register the device when such a user logs in. | 15 const int64 kTokenFetchErrorDelayMilliseconds = 3 * 1000; |
| 32 const char* kNonManagedDomains[] = { | 16 // For unmanaged devices, check once per day whether they're still unmanaged. |
| 33 "@googlemail.com", | 17 const int64 kUnmanagedDeviceRefreshRateMilliseconds = 24 * 60 * 60 * 1000; |
| 34 "@gmail.com" | |
| 35 }; | |
| 36 | 18 |
| 37 // Checks the domain part of the given username against the list of known | |
| 38 // non-managed domain names. Returns false if |username| is empty or its | |
| 39 // in a domain known not to be managed. | |
| 40 bool CanBeInManagedDomain(const std::string& username) { | |
| 41 if (username.empty()) { | |
| 42 // This means incognito user in case of ChromiumOS and | |
| 43 // no logged-in user in case of Chromium (SigninService). | |
| 44 return false; | |
| 45 } | |
| 46 for (size_t i = 0; i < arraysize(kNonManagedDomains); i++) { | |
| 47 if (EndsWith(username, kNonManagedDomains[i], true)) { | |
| 48 return false; | |
| 49 } | |
| 50 } | |
| 51 return true; | |
| 52 } | 19 } |
| 53 | 20 |
| 54 } // namespace | |
| 55 | |
| 56 namespace policy { | 21 namespace policy { |
| 57 | 22 |
| 58 namespace em = enterprise_management; | 23 namespace em = enterprise_management; |
| 59 | 24 |
| 60 DeviceTokenFetcher::ObserverRegistrar::ObserverRegistrar() {} | 25 DeviceTokenFetcher::DeviceTokenFetcher( |
| 61 | 26 DeviceManagementService* service, |
| 62 DeviceTokenFetcher::ObserverRegistrar::~ObserverRegistrar() { | 27 CloudPolicyCache* cache) |
| 63 RemoveAll(); | 28 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 64 } | 29 Initialize(service, |
| 65 | 30 cache, |
| 66 void DeviceTokenFetcher::ObserverRegistrar::Init( | 31 kTokenFetchErrorDelayMilliseconds, |
| 67 DeviceTokenFetcher* token_fetcher) { | 32 kUnmanagedDeviceRefreshRateMilliseconds); |
| 68 RemoveAll(); | |
| 69 token_fetcher_ = token_fetcher; | |
| 70 } | |
| 71 | |
| 72 void DeviceTokenFetcher::ObserverRegistrar::AddObserver( | |
| 73 DeviceTokenFetcher::Observer* observer) { | |
| 74 observers_.push_back(observer); | |
| 75 token_fetcher_->AddObserver(observer); | |
| 76 } | |
| 77 | |
| 78 void DeviceTokenFetcher::ObserverRegistrar::RemoveAll() { | |
| 79 for (std::vector<DeviceTokenFetcher::Observer*>::iterator it = | |
| 80 observers_.begin(); it != observers_.end(); ++it) { | |
| 81 token_fetcher_->RemoveObserver(*it); | |
| 82 } | |
| 83 observers_.clear(); | |
| 84 } | 33 } |
| 85 | 34 |
| 86 DeviceTokenFetcher::DeviceTokenFetcher( | 35 DeviceTokenFetcher::DeviceTokenFetcher( |
| 87 DeviceManagementBackend* backend, | 36 DeviceManagementService* service, |
| 88 Profile* profile, | 37 CloudPolicyCache* cache, |
| 89 const FilePath& token_path) | 38 int64 token_fetch_error_delay_ms, |
| 90 : profile_(profile), | 39 int64 unmanaged_device_refresh_rate_ms) |
| 91 token_path_(token_path), | 40 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 92 backend_(backend), | 41 Initialize(service, |
| 93 state_(kStateNotStarted), | 42 cache, |
| 94 device_token_load_complete_event_(true, false) { | 43 token_fetch_error_delay_ms, |
| 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 44 unmanaged_device_refresh_rate_ms); |
| 96 | |
| 97 TokenService* token_service = profile_->GetTokenService(); | |
| 98 auth_token_ = token_service->GetTokenForService( | |
| 99 GaiaConstants::kDeviceManagementService); | |
| 100 | |
| 101 registrar_.Add(this, | |
| 102 NotificationType::TOKEN_AVAILABLE, | |
| 103 Source<TokenService>(token_service)); | |
| 104 // Register for the event of user login. The device management token won't | |
| 105 // be fetched until we know the domain of the currently logged in user. | |
| 106 #if defined(OS_CHROMEOS) | |
| 107 registrar_.Add(this, | |
| 108 NotificationType::LOGIN_USER_CHANGED, | |
| 109 NotificationService::AllSources()); | |
| 110 #else | |
| 111 registrar_.Add(this, | |
| 112 NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, | |
| 113 Source<Profile>(profile_)); | |
| 114 #endif | |
| 115 } | 45 } |
| 116 | 46 |
| 117 DeviceTokenFetcher::~DeviceTokenFetcher() {} | 47 DeviceTokenFetcher::~DeviceTokenFetcher() { |
| 118 | 48 CancelDelayedWork(); |
| 119 void DeviceTokenFetcher::Observe(NotificationType type, | |
| 120 const NotificationSource& source, | |
| 121 const NotificationDetails& details) { | |
| 122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 123 if (type == NotificationType::TOKEN_AVAILABLE) { | |
| 124 if (Source<TokenService>(source).ptr() == profile_->GetTokenService()) { | |
| 125 const TokenService::TokenAvailableDetails* token_details = | |
| 126 Details<const TokenService::TokenAvailableDetails>(details).ptr(); | |
| 127 if (token_details->service() == GaiaConstants::kDeviceManagementService) { | |
| 128 if (!HasAuthToken()) { | |
| 129 auth_token_ = token_details->token(); | |
| 130 SendServerRequestIfPossible(); | |
| 131 } | |
| 132 } | |
| 133 } | |
| 134 #if defined(OS_CHROMEOS) | |
| 135 } else if (type == NotificationType::LOGIN_USER_CHANGED) { | |
| 136 SendServerRequestIfPossible(); | |
| 137 #else | |
| 138 } else if (type == NotificationType::GOOGLE_SIGNIN_SUCCESSFUL) { | |
| 139 if (profile_ == Source<Profile>(source).ptr()) { | |
| 140 SendServerRequestIfPossible(); | |
| 141 } | |
| 142 #endif | |
| 143 } else { | |
| 144 NOTREACHED(); | |
| 145 } | |
| 146 } | 49 } |
| 147 | 50 |
| 148 std::string DeviceTokenFetcher::GetCurrentUser() { | 51 void DeviceTokenFetcher::Reset() { |
| 149 #if defined(OS_CHROMEOS) | 52 SetState(STATE_INACTIVE); |
| 150 return chromeos::UserManager::Get()->logged_in_user().email(); | 53 backend_.reset(); |
| 151 #else | 54 } |
| 152 return profile_->GetBrowserSignin()->GetSignedInUsername(); | 55 |
| 153 #endif | 56 void DeviceTokenFetcher::FetchToken(const std::string& auth_token, |
| 57 const std::string& device_id) { |
| 58 // Construct a new backend, which will discard any previous requests. |
| 59 backend_.reset(service_->CreateBackend()); |
| 60 auth_token_ = auth_token; |
| 61 device_id_ = device_id; |
| 62 |
| 63 em::DeviceRegisterRequest request; |
| 64 backend_->ProcessRegisterRequest(auth_token, device_id, request, this); |
| 65 } |
| 66 |
| 67 const std::string& DeviceTokenFetcher::GetDeviceToken() { |
| 68 return device_token_; |
| 69 } |
| 70 |
| 71 void DeviceTokenFetcher::AddObserver(DeviceTokenFetcher::Observer* observer) { |
| 72 observer_list_.AddObserver(observer); |
| 73 } |
| 74 |
| 75 void DeviceTokenFetcher::RemoveObserver( |
| 76 DeviceTokenFetcher::Observer* observer) { |
| 77 observer_list_.RemoveObserver(observer); |
| 154 } | 78 } |
| 155 | 79 |
| 156 void DeviceTokenFetcher::HandleRegisterResponse( | 80 void DeviceTokenFetcher::HandleRegisterResponse( |
| 157 const em::DeviceRegisterResponse& response) { | 81 const em::DeviceRegisterResponse& response) { |
| 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 159 DCHECK_EQ(kStateRequestingDeviceTokenFromServer, state_); | |
| 160 if (response.has_device_management_token()) { | 82 if (response.has_device_management_token()) { |
| 161 device_token_ = response.device_management_token(); | 83 device_token_ = response.device_management_token(); |
| 162 BrowserThread::PostTask( | 84 SetState(STATE_TOKEN_AVAILABLE); |
| 163 BrowserThread::FILE, | |
| 164 FROM_HERE, | |
| 165 NewRunnableFunction(&WriteDeviceTokenToDisk, | |
| 166 token_path_, | |
| 167 device_token_, | |
| 168 device_id_)); | |
| 169 SetState(kStateHasDeviceToken); | |
| 170 } else { | 85 } else { |
| 171 NOTREACHED(); | 86 NOTREACHED(); |
| 172 SetState(kStateFailure); | 87 SetState(STATE_ERROR); |
| 173 } | 88 } |
| 174 } | 89 } |
| 175 | 90 |
| 176 void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) { | 91 void DeviceTokenFetcher::OnError(DeviceManagementBackend::ErrorCode code) { |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 178 // For privacy reasons, delete all identifying data when this device is not | |
| 179 // managed. | |
| 180 if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) { | 92 if (code == DeviceManagementBackend::kErrorServiceManagementNotSupported) { |
| 181 device_token_ = std::string(); | 93 cache_->SetDeviceUnmanaged(); |
| 182 device_id_ = std::string(); | 94 SetState(STATE_UNMANAGED); |
| 183 BrowserThread::PostTask( | |
| 184 BrowserThread::FILE, | |
| 185 FROM_HERE, | |
| 186 // The Windows compiler needs explicit template instantiation. | |
| 187 NewRunnableFunction<bool(*)(const FilePath&, bool), FilePath, bool>( | |
| 188 &file_util::Delete, token_path_, false)); | |
| 189 SetState(kStateNotManaged); | |
| 190 return; | |
| 191 } | 95 } |
| 192 SetState(kStateFailure); | 96 SetState(STATE_ERROR); |
| 193 } | 97 } |
| 194 | 98 |
| 195 void DeviceTokenFetcher::Restart() { | 99 void DeviceTokenFetcher::Initialize(DeviceManagementService* service, |
| 196 // Complain if there's currently an asynchronous operation going on. | 100 CloudPolicyCache* cache, |
| 197 DCHECK(state_ == kStateNotStarted || | 101 int64 token_fetch_error_delay_ms, |
| 198 state_ == kStateHasDeviceToken || | 102 int64 unmanaged_device_refresh_rate_ms) { |
| 199 state_ == kStateFailure || | 103 service_ = service; |
| 200 state_ == kStateNotManaged); | 104 cache_ = cache; |
| 201 device_token_.clear(); | 105 token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; |
| 202 device_token_load_complete_event_.Reset(); | 106 effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms; |
| 203 MakeReadyToRequestDeviceToken(); | 107 unmanaged_device_refresh_rate_ms_ = unmanaged_device_refresh_rate_ms; |
| 108 state_ = STATE_INACTIVE; |
| 109 delayed_work_task_ = NULL; |
| 110 |
| 111 if (cache_->is_device_unmanaged()) |
| 112 SetState(STATE_UNMANAGED); |
| 204 } | 113 } |
| 205 | 114 |
| 206 void DeviceTokenFetcher::StartFetching() { | 115 void DeviceTokenFetcher::SetState(FetcherState state) { |
| 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 116 state_ = state; |
| 208 if (state_ == kStateNotStarted) { | 117 if (state_ != STATE_ERROR) |
| 209 SetState(kStateLoadDeviceTokenFromDisk); | 118 effective_token_fetch_error_delay_ms_ = token_fetch_error_delay_ms_; |
| 210 // The file calls for loading the persisted token must be deferred to the | 119 |
| 211 // FILE thread. | 120 base::Time delayed_work_at; |
| 212 BrowserThread::PostTask( | 121 switch (state_) { |
| 213 BrowserThread::FILE, | 122 case STATE_INACTIVE: |
| 214 FROM_HERE, | 123 device_token_.clear(); |
| 215 NewRunnableMethod(this, | 124 auth_token_.clear(); |
| 216 &DeviceTokenFetcher::AttemptTokenLoadFromDisk)); | 125 device_id_.clear(); |
| 126 break; |
| 127 case STATE_TOKEN_AVAILABLE: |
| 128 FOR_EACH_OBSERVER(Observer, observer_list_, OnTokenAvailable()); |
| 129 break; |
| 130 case STATE_UNMANAGED: |
| 131 delayed_work_at = cache_->last_policy_refresh_time() + |
| 132 base::TimeDelta::FromMilliseconds(unmanaged_device_refresh_rate_ms_); |
| 133 break; |
| 134 case STATE_ERROR: |
| 135 delayed_work_at = cache_->last_policy_refresh_time() + |
| 136 base::TimeDelta::FromMilliseconds( |
| 137 effective_token_fetch_error_delay_ms_); |
| 138 effective_token_fetch_error_delay_ms_ *= 2; |
| 139 break; |
| 140 } |
| 141 |
| 142 CancelDelayedWork(); |
| 143 if (!delayed_work_at.is_null()) { |
| 144 base::Time now(base::Time::Now()); |
| 145 int64 delay = std::max<int64>((delayed_work_at - now).InMilliseconds(), 0); |
| 146 delayed_work_task_ = |
| 147 method_factory_.NewRunnableMethod(&DeviceTokenFetcher::DoDelayedWork); |
| 148 MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_work_task_, |
| 149 delay); |
| 217 } | 150 } |
| 218 } | 151 } |
| 219 | 152 |
| 220 void DeviceTokenFetcher::AttemptTokenLoadFromDisk() { | 153 void DeviceTokenFetcher::DoDelayedWork() { |
| 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 154 DCHECK(delayed_work_task_); |
| 222 if (file_util::PathExists(token_path_)) { | 155 delayed_work_task_ = NULL; |
| 223 std::string data; | |
| 224 em::DeviceCredentials device_credentials; | |
| 225 if (file_util::ReadFileToString(token_path_, &data) && | |
| 226 device_credentials.ParseFromArray(data.c_str(), data.size())) { | |
| 227 device_token_ = device_credentials.device_token(); | |
| 228 device_id_ = device_credentials.device_id(); | |
| 229 if (!device_token_.empty() && !device_id_.empty()) { | |
| 230 BrowserThread::PostTask( | |
| 231 BrowserThread::UI, | |
| 232 FROM_HERE, | |
| 233 NewRunnableMethod(this, | |
| 234 &DeviceTokenFetcher::SetState, | |
| 235 kStateHasDeviceToken)); | |
| 236 return; | |
| 237 } | |
| 238 } | |
| 239 } | |
| 240 | 156 |
| 241 BrowserThread::PostTask( | 157 switch (state_) { |
| 242 BrowserThread::UI, | 158 case STATE_INACTIVE: |
| 243 FROM_HERE, | 159 case STATE_TOKEN_AVAILABLE: |
| 244 NewRunnableMethod(this, | 160 break; |
| 245 &DeviceTokenFetcher::MakeReadyToRequestDeviceToken)); | 161 case STATE_UNMANAGED: |
| 246 } | 162 case STATE_ERROR: |
| 247 | 163 if (!auth_token_.empty() && !device_id_.empty()) |
| 248 void DeviceTokenFetcher::MakeReadyToRequestDeviceToken() { | 164 FetchToken(auth_token_, device_id_); |
| 249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 165 else |
| 250 SetState(kStateReadyToRequestDeviceTokenFromServer); | 166 NOTREACHED(); |
| 251 SendServerRequestIfPossible(); | 167 break; |
| 252 } | |
| 253 | |
| 254 void DeviceTokenFetcher::SendServerRequestIfPossible() { | |
| 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 256 std::string username = GetCurrentUser(); | |
| 257 if (state_ == kStateReadyToRequestDeviceTokenFromServer | |
| 258 && HasAuthToken() | |
| 259 && backend_ | |
| 260 && !username.empty()) { | |
| 261 if (CanBeInManagedDomain(username)) { | |
| 262 em::DeviceRegisterRequest register_request; | |
| 263 SetState(kStateRequestingDeviceTokenFromServer); | |
| 264 backend_->ProcessRegisterRequest(auth_token_, | |
| 265 GetDeviceID(), | |
| 266 register_request, | |
| 267 this); | |
| 268 } else { | |
| 269 SetState(kStateNotManaged); | |
| 270 } | |
| 271 } | 168 } |
| 272 } | 169 } |
| 273 | 170 |
| 274 bool DeviceTokenFetcher::IsTokenPending() { | 171 void DeviceTokenFetcher::CancelDelayedWork() { |
| 275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 172 if (delayed_work_task_) { |
| 276 return !device_token_load_complete_event_.IsSignaled(); | 173 delayed_work_task_->Cancel(); |
| 277 } | 174 delayed_work_task_ = NULL; |
| 278 | |
| 279 std::string DeviceTokenFetcher::GetDeviceToken() { | |
| 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 281 device_token_load_complete_event_.Wait(); | |
| 282 return device_token_; | |
| 283 } | |
| 284 | |
| 285 std::string DeviceTokenFetcher::GetDeviceID() { | |
| 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 287 // As long as access to this is only allowed from the UI thread, no explicit | |
| 288 // locking is necessary to prevent the ID from being generated twice. | |
| 289 if (device_id_.empty()) | |
| 290 device_id_ = GenerateNewDeviceID(); | |
| 291 return device_id_; | |
| 292 } | |
| 293 | |
| 294 void DeviceTokenFetcher::SetState(FetcherState state) { | |
| 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 296 if (state_ == state) | |
| 297 return; | |
| 298 state_ = state; | |
| 299 if (state == kStateFailure) { | |
| 300 device_token_load_complete_event_.Signal(); | |
| 301 NotifyTokenError(); | |
| 302 } else if (state == kStateNotManaged) { | |
| 303 device_token_load_complete_event_.Signal(); | |
| 304 NotifyNotManaged(); | |
| 305 } else if (state == kStateHasDeviceToken) { | |
| 306 device_token_load_complete_event_.Signal(); | |
| 307 NotifyTokenSuccess(); | |
| 308 } | 175 } |
| 309 } | 176 } |
| 310 | 177 |
| 311 void DeviceTokenFetcher::GetDeviceTokenPath(FilePath* token_path) const { | |
| 312 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 313 *token_path = token_path_; | |
| 314 } | |
| 315 | |
| 316 bool DeviceTokenFetcher::IsTokenValid() const { | |
| 317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 318 return state_ == kStateHasDeviceToken; | |
| 319 } | |
| 320 | |
| 321 // static | |
| 322 void DeviceTokenFetcher::WriteDeviceTokenToDisk( | |
| 323 const FilePath& path, | |
| 324 const std::string& device_token, | |
| 325 const std::string& device_id) { | |
| 326 em::DeviceCredentials device_credentials; | |
| 327 device_credentials.set_device_token(device_token); | |
| 328 device_credentials.set_device_id(device_id); | |
| 329 std::string data; | |
| 330 bool no_error = device_credentials.SerializeToString(&data); | |
| 331 DCHECK(no_error); | |
| 332 file_util::WriteFile(path, data.c_str(), data.length()); | |
| 333 } | |
| 334 | |
| 335 // static | |
| 336 std::string DeviceTokenFetcher::GenerateNewDeviceID() { | |
| 337 return guid::GenerateGUID(); | |
| 338 } | |
| 339 | |
| 340 } // namespace policy | 178 } // namespace policy |
| OLD | NEW |